﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Sockets;
using System.Windows;
using HslCommunication;
using HslCommunication.LogNet;
using System.Threading;
using System.Net;

namespace KeyencePLC
{
    public class PLC : IDisposable
    {

        #region 公共枚举
        public enum DataMode { Text, Hex }
        public enum LogMsgType { Incoming, Outgoing, Normal, Warning, Error, Copyright };
        #endregion


        #region PLC通信相关定义  Disposable注销
        private TcpClient _PLCTcpClient;
        private NetworkStream _PLCTcpStream;
        private string PLC_IP;
        private int PLC_Port;


        // The main control for communicating through the telnet port
        private Socket socket;
        private short[] parsedata = new short[10];
        protected bool sw_ugoahead;
        protected bool sw_igoahead;
        protected bool sw_echo;
        protected bool sw_termsent;



        private ILogNet logNet = new LogNetSingle(Application.ResourceAssembly + "\\Logs\\Log.txt");

        private DataMode CurrentDataMode
        {
            get
            {
                //if (rbHex.IsEnabled)
                //{
                //    return DataMode.Hex;
                //}
                //else
                //{
                //    return DataMode.Text;
                //}
                return DataMode.Hex;
            }
            set
            {
                //if (value == DataMode.Text)
                //{
                //    rbText.IsChecked = true;
                //    //MessageBox.Show(rbText.ToString());
                //}
                //else
                //{
                //    rbHex.IsChecked = true;
                //}
                // return DataMode.Hex;
            }
        }


        // Various colors for logging info
        private System.Drawing.Color[] LogMsgTypeColor = { System.Drawing.Color.Blue, System.Drawing.Color.Green, System.Drawing.Color.Black, System.Drawing.Color.Orange, System.Drawing.Color.Red, System.Drawing.Color.OrangeRed };

        // Temp holder for whether a key was pressed
        private bool KeyHandled = false;

        private int checkPrint;

        //判断回收状态
        bool _disposed;

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        ~PLC()
        {
            Dispose(false);
        }
        protected virtual void Dispose(bool disposing)
        {
            if (_disposed) return;
            if (disposing)
            {

            }
            _disposed = true;
        }
        public bool _isConnected
        {
            get
            {
                return _PLCTcpClient.Connected;
            }
        }
        #endregion

        #region  PLC上位链路通信指令




        /// <summary>
        /// 功能 指令 相关页
        ///更改模式 Mn 13-10
        ///清除错误 ER 13-11
        ///错误编号确认? E 13-11
        ///查询机型? K 13-12
        ///动作模式确认? M 13-13
        ///时间设定 WRT 13-14
        ///强制置位/强制复位 ST/RS 13-15
        ///连续强制置位/连续强制复位 STS/RSS 13-16
        ///读取数据 RD 13-17
        ///读取连续数据 RDS 13-17
        ///读取连续数据 RDE 13-21
        ///写入数据 WR 13-22
        ///写入连续数据 WRS 13-22
        ///写入连续数据 WRE 13-23
        ///写入设定值 WS 13-24
        ///写入连续设定值 WSS 13-24
        ///监控器登录 MBS/MWS 13-24
        ///读取监控器 MBR/MWR 13-27
        ///注释读取 RDC 13-28
        ///库切换 BE 13-29
        ///读取扩展单元缓冲存储器 URD 13-30
        ///写入扩展单元缓冲存储器 UWR 13-31
        /// </summary>
        public enum QueryType

        {
            /// <summary>
            /// ProgramMode
            /// </summary>
            ProgramMode,
            /// <summary>
            /// RunMode
            /// </summary>
            Run,
            //ER清除
            /// <summary>
            ///  //ER : 清除单元中发生的错误
            /// </summary>
            ER,
            /// <summary>
            /// //响应
            /// </summary>
            OK,

            /// <summary>
            /// //?E : 单元错误编号 //错误编号确认 ？E
            /// 编号错误内容编号错误内容编号错误内容
            ///010 子程序嵌套超限059 单元版本错误118 非法传输数据
            ///011 FOR-NEXT 嵌套超限063 需要重新接通电源120 看门狗定时器
            ///015 转换错误080 FLASH ROM 异常122 系统错误
            ///022 宏嵌套超限083 电池电压降低125 错误缓存溢出
            ///027 非法对象085 时钟数据消失127 自动加载失败
            ///029 梯形图堆栈错误086 RTC异常128 梯形图运算错误
            ///030 扫描时间超时087 存储卡异常129 单元错误
            ///031 梯形图堆栈溢出088 存储卡被拔出了131 FLASH ROM 格式
            ///040 无梯形图程序089 存储体访问中电源断开132 梯形图文件不正确
            ///050 单元设定检验和异常090 存储体访问完成等待134 自动加载文件夹
            ///051 单元设定信息未设定092 访问窗异常135 存储卡盖板打开
            ///052 单元未连接095 文件访问中136 存储卡被锁定
            ///053 扩展总线单元超时102 断电错误137 不支持的存储卡种类
            ///054 单元台数不一致103 电源中断处理超限141 CPU 存储器写入频率超限
            ///055 单元种类不一致106 复位异常142 CPU 存储器累积写入次数警告
            ///056 扩展总线通信错误107 系统错误143 CPU 存储器累积写入次数超限
            ///057 结束单元未连接
            /// </summary>
            EN,

            /// <summary>
            /// //?E : 用于查看 PLC 的型号。//?K 机型的问询
            /// </summary>
            PLC_K,


            /// <summary>
            /// 用于查看 CPU 单元当前的运行状态。
            /// </summary>
            MC,

            //错误编号
            /// <summary> 
            /// 软元件编号异常  • 指定的软元件编号、存储体编号、单元 编号、地址超出了范围。
            /// </summary>
            E0,
            //• 指定了程序中没有使用的计时器、计数器、CTH、CTC 编号。• 没有执行监控器登录，但是执行了监控器读取。
            /// <summary>
            /// //E1 :命令异常  • 发送了不支持的指令。• 指定指令的方法不正确。
            /// </summary>
            E1,
            /// <summary>
            /// //E2 : 未登录程序 • CPU 单元中没有登录程序的状态下，发送了“M1（切换到 RUN 模式）”指令。 
            /// </summary>
            E2,
            //CPU 单元的 RUN/PROG 开关在 PROG状态下，发送了“M1（切换到 RUN 模式）”指令
            /// <summary>
            /// 
            /// </summary>
            E3,//E3 : 
               /// <summary>
               /// //E4 : 禁止写入• 企图对禁止写入的程序更改计时器、计数器、的设定值
               /// </summary>
            E4,
            /// <summary>
            /// //E5 : 单元错误 在没有清除 CPU 单元错误的状态下，发送了 “M1（切换到 RUN 模式）”指令。 \
            /// </summary>
            E5,
            /// <summary>
            /// //E5 : 注释读取“RDC”指令选中的软元件中没有登录注释。PLC 的负荷较高，读取注释失败
            /// </summary>
            E6,

            /// <summary>
            /// //强制置位  ST_软元件种类+软元件编号 0D  // 53 54 20 52 30 30 30 30 35 0D（强制置位 R00005）
            /// </summary>

            ST,
            //强制复位
            /// <summary>
            /// //强制复位
            /// </summary>
            RS,

            /// <summary>
            /// //  继电器 00000～199915
            /// </summary>
            R,
            /// <summary>
            /// //链路继电器 0000～7FFF
            /// </summary>
            B,
            /// <summary>
            /// //内部辅助继电器 00000～399915
            /// </summary>
            MR,
            /// <summary>
            /// //锁存继电器 00000～99915
            /// </summary>
            LR,
            /// <summary>
            ///  //控制继电器 0000～7915
            /// </summary>
            CR,
            /// <summary>
            ///  //定时器 0000～3999
            /// </summary>
            T,
            /// <summary>
            /// //计数器 C 0000～3999
            /// </summary>
            C,
            /// <summary>
            /// //工作继电器 VB 0000～F9FF
            /// </summary>
            VB,



            //可将软元件的数据格式（后缀）指定为.U/.S/.D/.L/.H/（不指定）。
            //.U ： 16 位无符号十进制数
            //.S ： 16 位有符号十进制数
            //.D ： 32 位无符号十进制数
            //.L ： 32 位有符号十进制数
            //.H ： 16 位十六进制数
            //（不指定）：因软元件类型而异



            //软元件种类 软元件编号*1  数据格式无指定 读取个数
            //软元件名称 KV-7500/7300                   位/.U/.S/.H  .D/.L
            //继电器*2 R（可省略） 00000～199915*3 （位） 0001～1000 0001～0500
            //链路继电器 B 0000～7FFF （位） 0001～1000 0001～0500
            //内部辅助继电器*2 MR 00000～399915 （位） 0001～1000 0001～0500
            //锁存继电器*2 LR 00000～99915 （位） 0001～1000 0001～0500
            //控制继电器 CR 0000～7915 （位） 0001～1000 0001～0500
            //工作继电器 VB 0000～F9FF （位） 0001～1000 0001～0500
            //数据存储器*2 DM 00000～65534 .U 0001～1000 0001～0500
            //扩展数据存储器*2 EM 00000～65534 .U 0001～1000 0001～0500
            //文件寄存器*2 FM 00000～32767 .U 0001～1000 0001～0500
            //ZF 00000～524287 .U 0001～1000 0001～0500
            //链路寄存器 W 0000～7FFF.U 0001～1000 0001～0500
            //临时数据存储器 TM 000～511 .U 001～512 001～256
            //变址寄存器 Z 01～12 .U 01～12 01～12
            //计时器 T 0000～3999 .D 001～120 001～120
            //计时器（当前值） TC 0000～3999 .D 001～120 001～120
            //计时器（设定值） TS 0000～3999 .D 001～120 001～120
            //计数器 C 0000～3999 .D 001～120 001～120
            //计数器（当前值） CC 0000～3999 .D 001～120 001～120
            //计数器（设定值） CS 0000～3999 .D 001～120 001～120
            //数字微调器 AT 0～7 .D 1～8 1～8
            //控制存储器 CM 0000～5999 .U 0001～1000 0001～0500
            //工作存储器 VM 00000～50999 .U 0001～1000 0001～0500

            /// <summary>
            /// //数据存储器  00000～65534  .U  0001～1000 0001～0500
            /// </summary>
            DM,
            /// <summary>
            /// //扩展数据存储器 00000～65534 .U 0001～1000 0001～0500
            /// </summary>
            EM,
            /// <summary>
            ///  //文件寄存器 00000～32767 .U 0001～1000 0001～0500
            /// </summary>
            FM,
            /// <summary>
            /// // 文件寄存器 00000～524287 .U 0001～1000 0001～0500
            /// </summary>
            ZF,
            /// <summary>
            /// //链路寄存器 0000～7FFF .U 0001～1000 0001～0500
            /// </summary>
            W,
            /// <summary>
            /// //临时数据存储器 TM 000～511 .U 001～512 001～256
            /// </summary>
            TM,
            /// <summary>
            /// //变址寄存器 Z 01～12 .U 01～12 01～12
            /// </summary>
            Z,
            /// <summary>
            /// //计时器（当前值） TC 0000～3999 .D 001～120 001～120
            /// </summary>
            TC,
            /// <summary>
            /// //计时器（设定值） TS 0000～3999 .D 001～120 001～120
            /// </summary>
            TS,
            /// <summary>
            /// //计数器（当前值） CC 0000～3999 .D 001～120 001～120
            /// </summary>
            CC,
            /// <summary>
            /// //计数器（设定值） CS 0000～3999 .D 001～120 001～120
            /// </summary>
            CS,
            /// <summary>
            /// //数字微调器 AT 0～7 .D 1～8 1～8
            /// </summary>
            AT,
            /// <summary>
            /// //控制存储器 CM 0000～5999 .U 0001～1000 0001～0500
            /// </summary>
            CM,
            /// <summary>
            /// //工作存储器 VM 00000～50999 .U 0001～1000 0001～0500
            /// </summary>
            VM,




            _0, //0
            _1, //1
            _2, //2
            _3, //3
            _4, //4
            _5, //5
            _6, //6
            _7, //7
            _8,//8
            _9, //9

            //响应 OK 或者E错误




            //软元件种类 软元件编号*1
            //写入个数 软元件名称 KV-7500/7300
            //继电器*2 R(可省略) 00000～199915*3 01～16
            //链路继电器 B 0000～7FFF 01～16
            //内部辅助继电器*2 MR 00000～399915 01～16
            //锁存继电器*2 LR 00000～99915 01～16
            //控制继电器 CR 0000～7915 01～16
            //工作继电器 VB 0000～F9FF 01～16

            /// <summary>
            /// 连续强制置位/强制复位//<连续强制置位> STS 软元件种类+软元件编号 写入个数 0D //   53 54 53 20 52 30 30 30 30 35 20 30 31 30 0D（强制置位 R00005-R00015）
            /// </summary>
            STS,

            /// <summary>
            /// 连续强制复位 RSS 软元件种类+软元件编号 写入个数 0D 写入01-16
            /// </summary>
            RSS,

            //x响应OK E错误编号



            /// <summary>
            /// 读取数据 [RD]//RD: 读取一个指定软元件的数据。 RD 软元件种类+软元件编号+数据格式+0D  //RD 52 44 20 52 30 30 30 31 30 0D 读取R00010的数据
            /// </summary>
            RD,

            /// <summary>
            /// /读取连续数据 [RDS]
            /// </summary>
            RDS, //?E : 单元错误编号

            /// <summary>
            /// /读取连续数据 同[RDS]
            /// </summary>
            RDE,

            /// <summary>
            /// .U ：16 位无符号十进制数
            /// </summary>
            DOTU, //U
                  /// <summary>
                  /// .S ：16 位有符号十进制数
                  /// </summary>
            DOTS, //S
                  /// <summary>
                  /// .D ：32 位无符号十进制数
                  /// </summary>
            DOTD, //D 
                  /// <summary>
                  /// .L ：32 位有符号十进制数
                  /// </summary>
            DOTL,//L

            /// <summary>
            /// 
            /// .H ：16 位十六进制值数
            /// </summary>
            DOTH, //H


            //响应
            //<R, B, MR, LR, CR, VB>  数据1 数据2 ... 数据n 0D 0A
            //* n ：发送指令时指定的读取个数
            //数据1~n ： 从指定的软元件编号开始，依次显示软元件中存储的值。
            //发送指令时指定的数据格式不同，值的范围也不同。

            //指定的数据格式 数据1~n
            //大小 范围
            //无指定 位 1字节 0 (OFF) 或1(ON)
            //.U 十进制数16位无符号 5字节 00000～65535
            //.S 十进制数16位有符号 6字节 －32768～＋32767 (0は＋00000)
            //.D 十进制数32位无符号 10字节 0000000000～4294967295
            //.L 十进制数32位有符号 11字节 －2147483648～＋2147483647
            //(0为＋0000000000)
            //.H 十六进制数16位 4字节 0000～FFFF

            //指定了.U/.S/.H 数据格式时，处理连续 16 位。
            //• 指定了.U/.S/.H 数据格式时，处理连续 16 位。
            //• 指定的继电器软元件不是通道的首软元件（R002、MR311 等）时，将跨到下一个通道处
            //理连续 16/32 位。



            //<DM, EM, FM, ZF, W, TM, Z, AT, CM, VM>
            //* n: 发送指令时指定的读取个数
            //数据1～n ： 从指定的软元件编号开始，依次显示软元件中存储的值。
            //发送指令时指定的数据格式不同，值的范围也不同。

            //n: 发送指令时指定的读取个数
            //数据1～n ： 从指定的软元件编号开始，依次显示软元件中存储的值。
            //发送指令时指定的数据格式不同，值的范围也不同。
            //            指定的数据格式 数据1～n
            //大小 范围
            //.U(可省略) 十进制数16位无符号 5字节 00000～65535
            //.S 十进制数16位有符号 6字节 －32768～＋32767 (0为＋00000)
            //.D 十进制数32位无符号 10字节 0000000000～4294967295
            //.L 十进制数32位有符号 11字节 －2147483648～＋2147483647
            //(0为＋0000000000)
            //.H 十六进制数16位 4字节 0000～FFFF

            //• 对 Z 指定了.U/.S/.H 时，显示低位 16 位的值。
            //• 对 AT 指定了.U/.S/.H 时，显示低位 16 位的值。
            //错误响应同上


            // 将 R100～R103 以数据格式“位”读取时
            //            RDS R100  4CR
            //   52H 44H 53H 20H 20H 52H 31H 30H 30H 34H0DH
            //        响应

            //R100:ON R101:OFF R102:ON R103:OFF


            //读取连续数据 [RDE 与RDS相同




            //软元件种类 软元件编号*1
            //数据格式
            //无指定
            //写入个数
            //软元件名称 KV-7500/7300 位
            ///.U/.S/.H.D/.L
            //继电器*2 R（可省略） 00000～199915*5 （位） 0001～1000 0001～0500
            //链路继电器 B 0000～7FFF （位） 0001～1000 0001～0500
            //内部辅助继电器*2 MR 00000～399915 （位） 0001～1000 0001～0500
            //锁存继电器*2 LR 00000～99915 （位） 0001～1000 0001～0500
            //控制继电器 CR 0000～7915 （位） 0001～1000 0001～0500
            //工作继电器 VB 0000～F9FF （位） 0001～1000 0001～0500
            //数据存储*2 DM 00000～65534 .U 0001～1000 0001～0500
            //扩展数据存储*2 EM 00000～65534 .U 0001～1000 0001～0500
            //文件寄存器*2 FM 00000～32767 .U 0001～1000 0001～0500
            //             ZF 00000～524287 .U 0001～1000 0001～0500
            //链路寄存器 W 0000～7FFF.U 0001～1000 0001～0500
            //临时数据存储器 TM 000～511 .U 001～512 001～256
            //变址寄存器 Z 01～12 .U 01～12 01～12
            //定时器（当前值）*4 T*3, TC 0000～3999 .D 001～120 001～120
            //定时器（设定值）*4 TS 0000～3999 .D 001～120 001～120
            //计数器（当前值）*4 C*3, CC 0000～3999 .D 001～120 001～120
            //计数器（设定值）*4 CS 0000～3999 .D 001～120 001～120
            //控制存储器 CM 0000～5999 .U 0001～1000 0001～0500
            //工作存储器 VM 00000～63999 （位） 0001～1000 0001～0500
            //        *1 软元件编号、写入个数可以清零。
            //*2 可对继电器、内部辅助继电器、锁存继电器、数据存储器、扩展数据存储器、文件寄存器进行 XYM 表示。 “
            //XYM 表示”，第 13-33 页
            //*3 指定定时器（T）、计数器（C）时，向当前值执行写入。
            //*4 指定.U/.S/.H的数据格式后，写入低位16位。
            //*5 KV-7000 系列的 CPU 功能版本为 2.2 以下时，继电器的范围为 00000～99915。


            /// <summary>
            /// 写入数据 [WR]/写入连续数据 [WRS]/// WR :将数据写入指定的软元件。/// WRS :连续写入指定个数的数据。
            ///         ///*1 单元编号 ：在 00~48 的范围内指定单元编号。
            ///*2 地址 ：在0～59999的范围内指定扩展单元缓冲存储器的地址。
            ///*3 数据格式 ：软元件的数据格式（后缀）可指定为.U/.S/.D/.L/.H/（不指定）。
            ///.U ：16 位无符号十进制数
            ///.S ：16 位有符号十进制数
            ///.D ：32 位无符号十进制数
            ///.L ：32 位有符号十进制数
            ///.H ：16 位十六进制值数
            ///（不指定） ：因软元件类型而异
            ///“ 数据格式指定为.D/.L 时的数据同时性”，第 13-33 页
            ///数据格式的指定方法与 RD/RDS 指令相同。
            ///“读取数据[RD]/读取连续数据[RDS]”，第13-17页
            ///*4 读取个数 ：数据格式指定为.U/.S/.H 时，指定范围为 0001~1000。
            ///数据格式指定为.D/.L 时，指定范围为 0001~0500。
            ///响应 数据 数据 数据 数据 Cr Lf ||  数据: 指定地址的扩展单元缓冲存储器中存储的数据。读取结果的格式与 RDS 指令的响应格式相同。
            /// </summary>                   
            WR,//WR :将数据写入指定的软元件。 WR 软元件种类 软元件编号 数据格式 数据 0D


            /// <summary>
            ///  //WRS :连续写入指定个数的数据。WRE写入连续数据与WRS相同 WRS 软元件种类 软元件编号 数据格式/// 写入设定值 [WS]/写入连续设定值 [WSS]WS/WSS 指令为以太网单元 KV-LE20A 兼容指令。其动作与 WR/WRS 相同。 写入个数 数据1 数据2 .... 数据n 0D 
            ///          ///*1 单元编号 ：在 00~48 的范围内指定单元编号。
            ///*2 地址 ：在0～59999的范围内指定扩展单元缓冲存储器的地址。
            ///*3 数据格式 ：软元件的数据格式（后缀）可指定为.U/.S/.D/.L/.H/（不指定）。
            ///.U ：16 位无符号十进制数
            ///.S ：16 位有符号十进制数
            ///.D ：32 位无符号十进制数
            ///.L ：32 位有符号十进制数
            ///.H ：16 位十六进制值数
            ///（不指定） ：因软元件类型而异
            ///“ 数据格式指定为.D/.L 时的数据同时性”，第 13-33 页
            ///数据格式的指定方法与 RD/RDS 指令相同。
            ///“读取数据[RD]/读取连续数据[RDS]”，第13-17页
            ///*4 读取个数 ：数据格式指定为.U/.S/.H 时，指定范围为 0001~1000。
            ///数据格式指定为.D/.L 时，指定范围为 0001~0500。
            ///响应 数据 数据 数据 数据 Cr Lf ||  数据: 指定地址的扩展单元缓冲存储器中存储的数据。读取结果的格式与 RDS 指令的响应格式相同。
            /// </summary>
            WRS,

            /// <summary>
            /// 连续写入指定个数的数据。WRE写入连续数据与WRS相同 WRS 软元件种类 软元件编号 数据格式/// 写入设定值 [WS]/写入连续设定值 [WSS]WS/WSS 指令为以太网单元 KV-LE20A 兼容指令。其动作与 WR/WRS 相同。 写入个数 数据1 数据2 .... 数据n 0D 
            ///         ///*1 单元编号 ：在 00~48 的范围内指定单元编号。
            ///*2 地址 ：在0～59999的范围内指定扩展单元缓冲存储器的地址。
            ///*3 数据格式 ：软元件的数据格式（后缀）可指定为.U/.S/.D/.L/.H/（不指定）。
            ///.U ：16 位无符号十进制数
            ///.S ：16 位有符号十进制数
            ///.D ：32 位无符号十进制数
            ///.L ：32 位有符号十进制数
            ///.H ：16 位十六进制值数
            ///（不指定） ：因软元件类型而异
            ///“ 数据格式指定为.D/.L 时的数据同时性”，第 13-33 页
            ///数据格式的指定方法与 RD/RDS 指令相同。
            ///“读取数据[RD]/读取连续数据[RDS]”，第13-17页
            ///*4 读取个数 ：数据格式指定为.U/.S/.H 时，指定范围为 0001~1000。
            ///数据格式指定为.D/.L 时，指定范围为 0001~0500。
            ///响应 数据 数据 数据 数据 Cr Lf ||  数据: 指定地址的扩展单元缓冲存储器中存储的数据。读取结果的格式与 RDS 指令的响应格式相同。
            /// </summary>
            WRE,

            //         指令和响应示例
            // 数据格式指定为“位”，写入 R100 ~R103 //WRS R100 4 1 0 1 0 ||57 52 53 20 52 31 30 30 20 34 20 31 20 30 20 31 20 30 0D
            //   数据格式指定为“.S”，写入 DM200 ~ DM202 || WRS DM200.S 3 +15025 - 05400 200 Cr || 57 52 53 20 44 4D 32 30 30 2E 53 20 33 20 2B 31 35 30 32 35 20 2D 30 35 34 30 30 20 32 30 30 0D
            //   响应 OK 4F 4B 0D 0A   写入数据可以消零。数据为正数时，可省略“+”。
            //但是“软元件类型”只能指定“T”、“C”、“CTC”。指定了“T”、“C”时，写入设定值




            //或字软元件登录表(MWS)。
            // 最多可登录 120 个数据。
            // MBS ：对位软元件执行监控器登录。/// <位软元件监控器登录>   || MBS 软元件种类 软元件编号 软元件种类 软元件编号 ... 软元件种类 软元件编号 || 4D 42 53 20        20       20  0D

            /// <summary>
            /// 监控器登录 MBS MWS将指定的软元件登录到位软元件登录表(MBS)
            /// </summary>   
            MBS,

            //软元件种类软元件编号*1
            //软元件名称KV-7500/7300
            //继电器*2 R（可省略） 00000～199915*3
            //链路继电器B 0000～7FFF
            //内部辅助继电器*2 MR 00000～399915
            //锁存继电器*2 LR 00000～99915
            //控制继电器CR 0000～7915
            //定时器T 0000～3999
            //计数器C 0000～3999
            //工作继电器VB 0000～F9FF
            //
            /// <summary>
            /// MWS ：对字软元件执行监控器登录。 // 字软元件监控器登录  MWS 软元件种类 软元件编号 数据格式 软元件种类 软元件编号 数据格式 ... Cr || 4D 57 53 20      20       20       0D 
            /// </summary>
            MWS,

            //软元件种类软元件编号*1 数据格式
            //软元件名 KV-7500/7300 无指定
            //继电器*2*3 R（可省略） 00000～199915*4 .U
            //链路继电器*3 B 0000～7FFF.U
            //内部辅助继电器*2*3 MR 00000～399915 .U
            //锁存继电器*2*3 LR 00000～99915 .U
            //控制继电器*3 CR 0000～7915 .U
            //工作继电器VB 0000～F9FF.U
            //数据存储*2 DM 00000～65534 .U
            //扩展数据存储*2 EM 00000～65534 .U
            //文件寄存器*2 FM 00000～32767 .U
            //ZF 00000～524287 .U
            //链路寄存器W 0000～7FFF.U
            //临时数据存储器TM 000～511 .U
            //变址寄存器Z 01～12 .U
            //定时器(当前值) TC 0000～3999 .D
            //定时器(设定值) TS 0000～3999 .D
            //计数器(当前值) CC 0000～3999 .D
            //计数器(设定值) CS 0000～3999 .D
            //控制存储器CM 0000～5999 .U
            //工作存储器VM 0000～50999 .U

            //响应  OK 4F 4B  || 异常 E



            /// <summary>
            /// 监控读取 [ MBR ]／[ MWR ]//指令 读取软元件登录表 M B R CR ||  4DH 42H 52H 0DH
            /// 用于读取软元件登录表的软元件值。MBR ：读取监控器登录后的位软元件值。 MWR ：读取监控器登录后的字软元件值。       
            /// </summary>
            MBR,


            /// <summary>
            /// 读取字软元件登录表 M W R CR || 4DH 57H 52H 0DH
            /// </summary>
            MWR,


            //响应 数据 20 数据 20 数据 20 数据 0D 0A 
            //数据: 位软元件登录表或字软元件登录表中登录的软元件监控器结果。监控结果的格式与 RDS 指令的响应格式相同。
            //错误响应  E 1 CR LF || 45H 31H 0DH 0AH 命令异常


            //软元件种类软元件编号*1
            //软元件名称KV-7500/7300
            //继电器*2 R（可省略） 00000～199915*3
            //链路继电器B 0000～7FFF
            //内部辅助继电器*2 MR 00000～399915
            //锁存继电器*2 LR 00000～99915
            //控制继电器CR 0000～7915
            //数据存储*2 DM 00000～65534
            //扩展数据存储*2 EM 00000～65534
            //文件寄存器*2 FM 00000～32767
            //ZF 000000～524287
            //链路寄存器W 0000～7FFF
            //临时数据存储器TM 000～511
            //变址寄存器Z 01～12
            //定时器T 0000～3999
            //计数器C 0000～3999
            //控制存储CM 0000～5999



            /// <summary>
            /// 注释读取 [RDC]  用于读取指定软元件的注释。指令  RDC 用于读取指定软元件的注释 RDC 软元件种类R 软元件编号100 Cr || 52 44 43 20 52 31 30 30 0D
            /// 响应  数据CR LF 数据: 指令指定的软元件注释（32 字符）。注释在 32 字符以内时，添加空格(20H)。
            ///         ///*1 单元编号 ：在 00~48 的范围内指定单元编号。
            ///*2 地址 ：在0～59999的范围内指定扩展单元缓冲存储器的地址。
            ///*3 数据格式 ：软元件的数据格式（后缀）可指定为.U/.S/.D/.L/.H/（不指定）。
            ///.U ：16 位无符号十进制数
            ///.S ：16 位有符号十进制数
            ///.D ：32 位无符号十进制数
            ///.L ：32 位有符号十进制数
            ///.H ：16 位十六进制值数
            ///（不指定） ：因软元件类型而异
            ///“ 数据格式指定为.D/.L 时的数据同时性”，第 13-33 页
            ///数据格式的指定方法与 RD/RDS 指令相同。
            ///“读取数据[RD]/读取连续数据[RDS]”，第13-17页
            ///*4 读取个数 ：数据格式指定为.U/.S/.H 时，指定范围为 0001~1000。
            ///数据格式指定为.D/.L 时，指定范围为 0001~0500。
            ///响应 数据 数据 数据 数据 Cr Lf ||  数据: 指定地址的扩展单元缓冲存储器中存储的数据。读取结果的格式与 RDS 指令的响应格式相同。
            /// 根据项目语言设定，输入转换后的字符串。在 RUN 模式下写入时，即使指定的软元件中登录了注释，也会显示异常时的响应 E6。
            /// </summary>
            RDC,



            /// <summary>
            /// 库切换 BE  切换文件寄存器的库。/// 响应  O K CR LF || 4FH 4BH 0DH 0AH  ||OK ：指令正常处理时，输入表示该状态的代码“OK”。
            /// // 库编号 ：对于文件寄存器的库编号按照 0～15 的范围进行指定。 BE 库编号0 Cr || 42 45 20  30 0D
            /// </summary>

            BE,

            /// <summary>
            /// 读取扩展单元缓冲存储器 [URD]  用于从扩展单元缓冲存储器中连续读取指定个数的数据。
            /// URD 单元编号 地址 数据格式 读取个数 Cr || 55 52 44 20 30 31 20 30 30 30 31 30 31 30 30 0D || URD 01 0001 0100 
            ///         ///*1 单元编号 ：在 00~48 的范围内指定单元编号。
            ///*2 地址 ：在0～59999的范围内指定扩展单元缓冲存储器的地址。
            ///*3 数据格式 ：软元件的数据格式（后缀）可指定为.U/.S/.D/.L/.H/（不指定）。
            ///.U ：16 位无符号十进制数
            ///.S ：16 位有符号十进制数
            ///.D ：32 位无符号十进制数
            ///.L ：32 位有符号十进制数
            ///.H ：16 位十六进制值数
            ///（不指定） ：因软元件类型而异
            ///“ 数据格式指定为.D/.L 时的数据同时性”，第 13-33 页
            ///数据格式的指定方法与 RD/RDS 指令相同。
            ///“读取数据[RD]/读取连续数据[RDS]”，第13-17页
            ///*4 读取个数 ：数据格式指定为.U/.S/.H 时，指定范围为 0001~1000。
            ///数据格式指定为.D/.L 时，指定范围为 0001~0500。
            ///响应 数据 数据 数据 数据 Cr Lf ||  数据: 指定地址的扩展单元缓冲存储器中存储的数据。读取结果的格式与 RDS 指令的响应格式相同。
            /// </summary>

            URD, //URD 用于从扩展单元缓冲存储器中连续读取指定个数的数据。


            /// <summary>
            /// 写入扩展单元缓冲存储器 [UWR] 用于向扩展单元缓冲存储器连续写入指定个数的数据。\
            /// UWR 01 10000 .U 01 01 01 01 Cr || 55 57 52 20 30 31 20 31 30 30 30 30 2E 55 20 30 31 20 30 31 20 30 31 0D
            ///         ///*1 单元编号 ：在 00~48 的范围内指定单元编号。
            ///*2 地址 ：在0～59999的范围内指定扩展单元缓冲存储器的地址。
            ///*3 数据格式 ：软元件的数据格式（后缀）可指定为.U/.S/.D/.L/.H/（不指定）。
            ///.U ：16 位无符号十进制数
            ///.S ：16 位有符号十进制数
            ///.D ：32 位无符号十进制数
            ///.L ：32 位有符号十进制数
            ///.H ：16 位十六进制值数
            ///（不指定） ：因软元件类型而异
            ///“ 数据格式指定为.D/.L 时的数据同时性”，第 13-33 页
            ///数据格式的指定方法与 RD/RDS 指令相同。
            ///“读取数据[RD]/读取连续数据[RDS]”，第13-17页
            ///*4 读取个数 ：数据格式指定为.U/.S/.H 时，指定范围为 0001~1000。
            ///数据格式指定为.D/.L 时，指定范围为 0001~0500。
            ///响应 数据 数据 数据 数据 Cr Lf ||  数据: 指定地址的扩展单元缓冲存储器中存储的数据。读取结果的格式与 RDS 指令的响应格式相同。
            /// </summary>

            UWR, //用于向扩展单元缓冲存储器连续写入指定个数的数据。


            /// <summary>
            /// XYM表示法
            /// </summary>
            /// 
            //软元件 名称可根据下表的 XYM 表示指定继电器(R)、内部辅助继电器(MR)、锁存继电器(LR)、数据存储器(DM)、扩展数据存储器(EM)、文件寄存器(FM)的软元件。
            //KEYENCE
            //表示XYM 表示
            //XYM 表示时的软元件编号
            //KV-7500/7300
            //继电器R
            //X 0000～1999F*
            //Y 0000～1999F*
            //内部辅助继电器MR M 00000～63999
            //锁存继电器LR L 0000～999F
            //数据存储器DM D 00000～65534
            //扩展数据存储器EM E 00000～65534
            //文件寄存器FM F 00000～32767


        }
        /// <summary>
        /// PLC 指令
        /// </summary>
        /// 

        //Mn模式更改
        public const string ProgramMode = ("4D 30 0D");
        public const string Run = ("4D 31 0D");
        public const string OK = ("4F 4B 0D 0A");
        public const string E0 = ("45 30 0A");  ////软元件编号异常  • 指定的软元件编号、存储体编号、单元 编号、地址超出了范围。
        //• 指定了程序中没有使用的计时器、计数器、CTH、CTC 编号。• 没有执行监控器登录，但是执行了监控器读取。
        public const string E1 = ("45 31 0A");  //E1 :命令异常  • 发送了不支持的指令。• 指定指令的方法不正确。
        public const string E2 = ("45 32 0A"); //E2 : 未登录程序 • CPU 单元中没有登录程序的状态下，发送了“M1（切换到 RUN 模式）”指令。 
        //CPU 单元的 RUN/PROG 开关在 PROG状态下，发送了“M1（切换到 RUN 模式）”指令
        public const string E3 = ("45 32 0A"); //E3 : 
        public const string E4 = ("45 32 0A"); //E4 : 禁止写入• 企图对禁止写入的程序更改计时器、计数器、的设定值
        public const string E5 = ("45 35 0A"); //E5 : 单元错误 在没有清除 CPU 单元错误的状态下，发送了 “M1（切换到 RUN 模式）”指令。 
        public const string E6 = ("45 36 0A"); //E5 : 注释读取“RDC”指令选中的软元件中没有登录注释。PLC 的负荷较高，读取注释失败


        //ER清除
        public const string ER = ("45 32 0A"); //ER : 清除单元中发生的错误
                                               //public const string OK = ("45 32 0A"); //响应

        //错误编号确认 ？E
        public const string EN = ("3F 45 0D"); //?E : 单元错误编号


        //?K 机型的问询

        public const string PLC_K = ("3F 4B 0D"); //?E : 用于查看 PLC 的型号。

        //响应
        public const string KV7300 = (" 35 34"); // KV-7300 ： ‘54’（ 35H、 34H）  
        public const string KV7500 = (" 35 35"); // KV-7500 ： ‘55’（ 35H、 35H）

        public const string MC = ("3F 4D 0D"); //用于查看 CPU 单元当前的运行状态。

        //强制置位 [ST]/强制复位 [RS]


        //软元件种类 软元件编号*1
        //写入个数 软元件名称 KV-7500/7300
        //继电器*2 R(可省略) 00000～199915*3 01～16
        //链路继电器 B 0000～7FFF 01～16
        //内部辅助继电器*2 MR 00000～399915 01～16
        //锁存继电器*2 LR 00000～99915 01～16
        //控制继电器 CR 0000～7915 01～16
        //工作继电器 VB 0000～F9FF 01～16

        //强制置位
        public const string ST = ("53 54 20"); //强制置位 ST_软元件种类+软元件编号 0D  // 53 54 20 52 30 30 30 30 35 0D（强制置位 R00005）
        //强制复位
        public const string RS = ("52 53 20"); //强制复位 

        public const string R = ("52");  //  继电器 00000～199915
        public const string B = ("42"); //链路继电器 0000～7FFF
        public const string MR = ("4D 52"); //内部辅助继电器 00000～399915
        public const string LR = ("4C 52"); //锁存继电器 00000～99915
        public const string CR = ("43 52"); //控制继电器 0000～7915
        public const string T = ("54"); //定时器 0000～3999
        public const string C = ("43"); //计数器 C 0000～3999
        public const string VB = ("56 42"); //工作继电器 VB 0000～F9FF



        //可将软元件的数据格式（后缀）指定为.U/.S/.D/.L/.H/（不指定）。
        //.U ： 16 位无符号十进制数
        //.S ： 16 位有符号十进制数
        //.D ： 32 位无符号十进制数
        //.L ： 32 位有符号十进制数
        //.H ： 16 位十六进制数
        //（不指定）：因软元件类型而异



        //软元件种类 软元件编号*1  数据格式无指定 读取个数
        //软元件名称 KV-7500/7300                   位/.U/.S/.H  .D/.L
        //继电器*2 R（可省略） 00000～199915*3 （位） 0001～1000 0001～0500
        //链路继电器 B 0000～7FFF （位） 0001～1000 0001～0500
        //内部辅助继电器*2 MR 00000～399915 （位） 0001～1000 0001～0500
        //锁存继电器*2 LR 00000～99915 （位） 0001～1000 0001～0500
        //控制继电器 CR 0000～7915 （位） 0001～1000 0001～0500
        //工作继电器 VB 0000～F9FF （位） 0001～1000 0001～0500
        //数据存储器*2 DM 00000～65534 .U 0001～1000 0001～0500
        //扩展数据存储器*2 EM 00000～65534 .U 0001～1000 0001～0500
        //文件寄存器*2 FM 00000～32767 .U 0001～1000 0001～0500
        //ZF 00000～524287 .U 0001～1000 0001～0500
        //链路寄存器 W 0000～7FFF.U 0001～1000 0001～0500
        //临时数据存储器 TM 000～511 .U 001～512 001～256
        //变址寄存器 Z 01～12 .U 01～12 01～12
        //计时器 T 0000～3999 .D 001～120 001～120
        //计时器（当前值） TC 0000～3999 .D 001～120 001～120
        //计时器（设定值） TS 0000～3999 .D 001～120 001～120
        //计数器 C 0000～3999 .D 001～120 001～120
        //计数器（当前值） CC 0000～3999 .D 001～120 001～120
        //计数器（设定值） CS 0000～3999 .D 001～120 001～120
        //数字微调器 AT 0～7 .D 1～8 1～8
        //控制存储器 CM 0000～5999 .U 0001～1000 0001～0500
        //工作存储器 VM 00000～50999 .U 0001～1000 0001～0500

        public const string DM = ("44 4D"); //数据存储器  00000～65534  .U  0001～1000 0001～0500
        public const string EM = ("45 4D"); //扩展数据存储器 00000～65534 .U 0001～1000 0001～0500
        public const string FM = ("46 4D"); //文件寄存器 00000～32767 .U 0001～1000 0001～0500
        public const string ZF = ("3F 45 0D"); // 文件寄存器 00000～524287 .U 0001～1000 0001～0500
        public const string W = ("57"); //链路寄存器 0000～7FFF .U 0001～1000 0001～0500
        public const string TM = ("54 4D"); //临时数据存储器 TM 000～511 .U 001～512 001～256
        public const string Z = ("5A"); //变址寄存器 Z 01～12 .U 01～12 01～12
        public const string TC = ("54 43"); //计时器（当前值） TC 0000～3999 .D 001～120 001～120
        public const string TS = ("54 53"); //计时器（设定值） TS 0000～3999 .D 001～120 001～120
        public const string CC = ("43 43"); //计数器（当前值） CC 0000～3999 .D 001～120 001～120
        public const string CS = ("43 53 "); //计数器（设定值） CS 0000～3999 .D 001～120 001～120
        public const string AT = ("41 54"); //数字微调器 AT 0～7 .D 1～8 1～8
        public const string CM = ("43 4D"); //控制存储器 CM 0000～5999 .U 0001～1000 0001～0500
        public const string VM = ("5A"); //工作存储器 VM 00000～50999 .U 0001～1000 0001～0500




        public const string _0 = ("30"); //0
        public const string _1 = ("31"); //1
        public const string _2 = ("32"); //2
        public const string _3 = ("33"); //3
        public const string _4 = ("34"); //4
        public const string _5 = ("35"); //5
        public const string _6 = ("36"); //6
        public const string _7 = ("37"); //7
        public const string _8 = ("38"); //8
        public const string _9 = ("39"); //9

        //响应 OK 或者E错误



        /// <summary>
        /// 连续强制置位/强制复位
        /// </summary>
        /// 

        //软元件种类 软元件编号*1
        //写入个数 软元件名称 KV-7500/7300
        //继电器*2 R(可省略) 00000～199915*3 01～16
        //链路继电器 B 0000～7FFF 01～16
        //内部辅助继电器*2 MR 00000～399915 01～16
        //锁存继电器*2 LR 00000～99915 01～16
        //控制继电器 CR 0000～7915 01～16
        //工作继电器 VB 0000～F9FF 01～16

        public const string STS = ("53 54 53 20"); //<连续强制置位> STS 软元件种类+软元件编号 写入个数 0D //   53 54 53 20 52 30 30 30 30 35 20 30 31 30 0D（强制置位 R00005-R00015）
        public const string RSS = ("52 53 53 20"); //<连续强制置位 RSS 软元件种类+软元件编号 写入个数 0D 写入01-16

        //x响应OK E错误编号



        /// <summary>
        /// 读取数据 [RD]/读取连续数据 [RDS]
        /// </summary>


        public const string RD = ("52 44 20"); //RD: 读取一个指定软元件的数据。 RD 软元件种类+软元件编号+数据格式+0D  //RD 52 44 20 52 30 30 30 31 30 0D 读取R00010的数据
        public const string RDS = ("52 44 53 20"); //?E : 单元错误编号


        public const string DOTU = ("2E 55"); //U
        public const string DOTS = ("2E 53"); //S
        public const string DOTD = ("2E 44"); //D 
        public const string DOTL = ("2E 4C"); //L
        public const string DOTH = ("2E 48"); //H


        //响应
        //<R, B, MR, LR, CR, VB>  数据1 数据2 ... 数据n 0D 0A
        //* n ：发送指令时指定的读取个数
        //数据1~n ： 从指定的软元件编号开始，依次显示软元件中存储的值。
        //发送指令时指定的数据格式不同，值的范围也不同。

        //指定的数据格式 数据1~n
        //大小 范围
        //无指定 位 1字节 0 (OFF) 或1(ON)
        //.U 十进制数16位无符号 5字节 00000～65535
        //.S 十进制数16位有符号 6字节 －32768～＋32767 (0は＋00000)
        //.D 十进制数32位无符号 10字节 0000000000～4294967295
        //.L 十进制数32位有符号 11字节 －2147483648～＋2147483647
        //(0为＋0000000000)
        //.H 十六进制数16位 4字节 0000～FFFF

        //指定了.U/.S/.H 数据格式时，处理连续 16 位。
        //• 指定了.U/.S/.H 数据格式时，处理连续 16 位。
        //• 指定的继电器软元件不是通道的首软元件（R002、MR311 等）时，将跨到下一个通道处
        //理连续 16/32 位。



        //<DM, EM, FM, ZF, W, TM, Z, AT, CM, VM>
        //* n: 发送指令时指定的读取个数
        //数据1～n ： 从指定的软元件编号开始，依次显示软元件中存储的值。
        //发送指令时指定的数据格式不同，值的范围也不同。

        //n: 发送指令时指定的读取个数
        //数据1～n ： 从指定的软元件编号开始，依次显示软元件中存储的值。
        //发送指令时指定的数据格式不同，值的范围也不同。
        //            指定的数据格式 数据1～n
        //大小 范围
        //.U(可省略) 十进制数16位无符号 5字节 00000～65535
        //.S 十进制数16位有符号 6字节 －32768～＋32767 (0为＋00000)
        //.D 十进制数32位无符号 10字节 0000000000～4294967295
        //.L 十进制数32位有符号 11字节 －2147483648～＋2147483647
        //(0为＋0000000000)
        //.H 十六进制数16位 4字节 0000～FFFF

        //• 对 Z 指定了.U/.S/.H 时，显示低位 16 位的值。
        //• 对 AT 指定了.U/.S/.H 时，显示低位 16 位的值。
        //错误响应同上


        // 将 R100～R103 以数据格式“位”读取时
        //            RDS R100  4CR
        //   52H 44H 53H 20H 20H 52H 31H 30H 30H 34H0DH
        //        响应

        //R100:ON R101:OFF R102:ON R103:OFF


        //读取连续数据 [RDE 与RDS相同

        /// <summary>
        /// 写入数据 [WR]/写入连续数据 [WRS]
        /// </summary>
        /// WR :将数据写入指定的软元件。
        /// WRS :连续写入指定个数的数据。


        //软元件种类 软元件编号*1
        //数据格式
        //无指定
        //写入个数
        //软元件名称 KV-7500/7300 位
        ///.U/.S/.H.D/.L
        //继电器*2 R（可省略） 00000～199915*5 （位） 0001～1000 0001～0500
        //链路继电器 B 0000～7FFF （位） 0001～1000 0001～0500
        //内部辅助继电器*2 MR 00000～399915 （位） 0001～1000 0001～0500
        //锁存继电器*2 LR 00000～99915 （位） 0001～1000 0001～0500
        //控制继电器 CR 0000～7915 （位） 0001～1000 0001～0500
        //工作继电器 VB 0000～F9FF （位） 0001～1000 0001～0500
        //数据存储*2 DM 00000～65534 .U 0001～1000 0001～0500
        //扩展数据存储*2 EM 00000～65534 .U 0001～1000 0001～0500
        //文件寄存器*2 FM 00000～32767 .U 0001～1000 0001～0500
        //             ZF 00000～524287 .U 0001～1000 0001～0500
        //链路寄存器 W 0000～7FFF.U 0001～1000 0001～0500
        //临时数据存储器 TM 000～511 .U 001～512 001～256
        //变址寄存器 Z 01～12 .U 01～12 01～12
        //定时器（当前值）*4 T*3, TC 0000～3999 .D 001～120 001～120
        //定时器（设定值）*4 TS 0000～3999 .D 001～120 001～120
        //计数器（当前值）*4 C*3, CC 0000～3999 .D 001～120 001～120
        //计数器（设定值）*4 CS 0000～3999 .D 001～120 001～120
        //控制存储器 CM 0000～5999 .U 0001～1000 0001～0500
        //工作存储器 VM 00000～63999 （位） 0001～1000 0001～0500
        //        *1 软元件编号、写入个数可以清零。
        //*2 可对继电器、内部辅助继电器、锁存继电器、数据存储器、扩展数据存储器、文件寄存器进行 XYM 表示。 “
        //XYM 表示”，第 13-33 页
        //*3 指定定时器（T）、计数器（C）时，向当前值执行写入。
        //*4 指定.U/.S/.H的数据格式后，写入低位16位。
        //*5 KV-7000 系列的 CPU 功能版本为 2.2 以下时，继电器的范围为 00000～99915。



        public const string WR = ("57 52"); //WR :将数据写入指定的软元件。 WR 软元件种类 软元件编号 数据格式 数据 0D
        public const string WRS = ("57 52 53"); //WRS :连续写入指定个数的数据。 WRS 软元件种类 软元件编号 数据格式 写入个数 数据1 数据2 .... 数据n 0D 

        //         指令和响应示例
        // 数据格式指定为“位”，写入 R100 ~R103 //WRS R100 4 1 0 1 0 ||57 52 53 20 52 31 30 30 20 34 20 31 20 30 20 31 20 30 0D
        //   数据格式指定为“.S”，写入 DM200 ~ DM202 || WRS DM200.S 3 +15025 - 05400 200 Cr || 57 52 53 20 44 4D 32 30 30 2E 53 20 33 20 2B 31 35 30 32 35 20 2D 30 35 34 30 30 20 32 30 30 0D
        //   响应 OK 4F 4B 0D 0A   写入数据可以消零。数据为正数时，可省略“+”。
        /// <summary>
        /// WRE写入连续数据与WRS相同
        /// </summary>
        /// 写入设定值 [WS]/写入连续设定值 [WSS]WS/WSS 指令为以太网单元 KV-LE20A 兼容指令。其动作与 WR/WRS 相同。
        //但是“软元件类型”只能指定“T”、“C”、“CTC”。指定了“T”、“C”时，写入设定值




        ///监控器登录 MBS MWS将指定的软元件登录到位软元件登录表(MBS)或字软元件登录表(MWS)。
        /// 最多可登录 120 个数据。
        /// MBS ：对位软元件执行监控器登录。
        /// MWS ：对字软元件执行监控器登录。
        /// <位软元件监控器登录>   || MBS 软元件种类 软元件编号 软元件种类 软元件编号 ... 软元件种类 软元件编号 || 4D 42 53 20        20       20  0D

        public const string MBS = ("4D 42 53");

        //软元件种类软元件编号*1
        //软元件名称KV-7500/7300
        //继电器*2 R（可省略） 00000～199915*3
        //链路继电器B 0000～7FFF
        //内部辅助继电器*2 MR 00000～399915
        //锁存继电器*2 LR 00000～99915
        //控制继电器CR 0000～7915
        //定时器T 0000～3999
        //计数器C 0000～3999
        //工作继电器VB 0000～F9FF
        // 字软元件监控器登录  MWS 软元件种类 软元件编号 数据格式 软元件种类 软元件编号 数据格式 ... Cr || 4D 57 53 20       20       20       0D 

        public const string MWS = ("4D 57 53");

        //软元件种类软元件编号*1 数据格式
        //软元件名 KV-7500/7300 无指定
        //继电器*2*3 R（可省略） 00000～199915*4 .U
        //链路继电器*3 B 0000～7FFF.U
        //内部辅助继电器*2*3 MR 00000～399915 .U
        //锁存继电器*2*3 LR 00000～99915 .U
        //控制继电器*3 CR 0000～7915 .U
        //工作继电器VB 0000～F9FF.U
        //数据存储*2 DM 00000～65534 .U
        //扩展数据存储*2 EM 00000～65534 .U
        //文件寄存器*2 FM 00000～32767 .U
        //ZF 00000～524287 .U
        //链路寄存器W 0000～7FFF.U
        //临时数据存储器TM 000～511 .U
        //变址寄存器Z 01～12 .U
        //定时器(当前值) TC 0000～3999 .D
        //定时器(设定值) TS 0000～3999 .D
        //计数器(当前值) CC 0000～3999 .D
        //计数器(设定值) CS 0000～3999 .D
        //控制存储器CM 0000～5999 .U
        //工作存储器VM 0000～50999 .U

        //响应  OK 4F 4B  || 异常 E



        /// <summary>
        /// 监控读取 [ MBR ]／[ MWR ]
        /// </summary>
        /// 用于读取软元件登录表的软元件值。MBR ：读取监控器登录后的位软元件值。 MWR ：读取监控器登录后的字软元件值。
        /// 

        public const string MBR = ("4D 42 52 0D"); //指令 读取软元件登录表 M B R CR ||  4DH 42H 52H 0DH
        public const string MWR = ("4D 57 52 0D"); // <读取字软元件登录表>  M W R CR || 4DH 57H 52H 0DH

        //响应 数据 20 数据 20 数据 20 数据 0D 0A 
        //数据: 位软元件登录表或字软元件登录表中登录的软元件监控器结果。监控结果的格式与 RDS 指令的响应格式相同。
        //错误响应  E 1 CR LF || 45H 31H 0DH 0AH 命令异常

        /// <summary>
        /// 注释读取 [RDC]  用于读取指定软元件的注释。
        /// </summary>
        /// 

        //软元件种类软元件编号*1
        //软元件名称KV-7500/7300
        //继电器*2 R（可省略） 00000～199915*3
        //链路继电器B 0000～7FFF
        //内部辅助继电器*2 MR 00000～399915
        //锁存继电器*2 LR 00000～99915
        //控制继电器CR 0000～7915
        //数据存储*2 DM 00000～65534
        //扩展数据存储*2 EM 00000～65534
        //文件寄存器*2 FM 00000～32767
        //ZF 000000～524287
        //链路寄存器W 0000～7FFF
        //临时数据存储器TM 000～511
        //变址寄存器Z 01～12
        //定时器T 0000～3999
        //计数器C 0000～3999
        //控制存储CM 0000～5999



        public const string RDC = ("52 44 43"); ////指令  RDC 用于读取指定软元件的注释 RDC 软元件种类R 软元件编号100 Cr || 52 44 43 20 52 31 30 30 0D
        //响应  数据CR LF 数据: 指令指定的软元件注释（32 字符）。注释在 32 字符以内时，添加空格(20H)。
        //根据项目语言设定，输入转换后的字符串。在 RUN 模式下写入时，即使指定的软元件中登录了注释，也会显示异常时的响应 E6。


        /// <summary>
        /// 库切换 BE  切换文件寄存器的库。
        /// </summary>
        /// 响应  O K CR LF || 4FH 4BH 0DH 0AH  ||OK ：指令正常处理时，输入表示该状态的代码“OK”。


        public const string BE = ("42 45"); // 库编号 ：对于文件寄存器的库编号按照 0～15 的范围进行指定。 BE 库编号0 Cr || 42 45 20  30 0D

        /// <summary>
        /// 读取扩展单元缓冲存储器 [URD]  用于从扩展单元缓冲存储器中连续读取指定个数的数据。
        /// </summary>
        /// URD 单元编号 地址 数据格式 读取个数 Cr || 55 52 44 20 30 31 20 30 30 30 31 30 31 30 30 0D || URD 01 0001 0100 
        //*1 单元编号 ：在 00~48 的范围内指定单元编号。
        //*2 地址 ：在0～59999的范围内指定扩展单元缓冲存储器的地址。
        //*3 数据格式 ：软元件的数据格式（后缀）可指定为.U/.S/.D/.L/.H/（不指定）。
        //.U ：16 位无符号十进制数
        //.S ：16 位有符号十进制数
        //.D ：32 位无符号十进制数
        //.L ：32 位有符号十进制数
        //.H ：16 位十六进制值数
        //（不指定） ：因软元件类型而异
        //“ 数据格式指定为.D/.L 时的数据同时性”，第 13-33 页
        //数据格式的指定方法与 RD/RDS 指令相同。
        //“读取数据[RD]/读取连续数据[RDS]”，第13-17页
        //*4 读取个数 ：数据格式指定为.U/.S/.H 时，指定范围为 0001~1000。
        //数据格式指定为.D/.L 时，指定范围为 0001~0500。
        //响应 数据 数据 数据 数据 Cr Lf ||  数据: 指定地址的扩展单元缓冲存储器中存储的数据。读取结果的格式与 RDS 指令的响应格式相同。

        public const string URD = ("55 52 44"); //URD 用于从扩展单元缓冲存储器中连续读取指定个数的数据。


        /// <summary>
        /// 写入扩展单元缓冲存储器 [UWR] 用于向扩展单元缓冲存储器连续写入指定个数的数据。
        /// </summary>
        /// UWR 01 10000 .U 01 01 01 01 Cr || 55 57 52 20 30 31 20 31 30 30 30 30 2E 55 20 30 31 20 30 31 20 30 31 0D
        public const string UWR = ("55 57 52"); //用于向扩展单元缓冲存储器连续写入指定个数的数据。


        /// <summary>
        /// XYM表示法
        /// </summary>
        /// 
        //软元件 名称可根据下表的 XYM 表示指定继电器(R)、内部辅助继电器(MR)、锁存继电器(LR)、数据存储器(DM)、扩展数据存储器(EM)、文件寄存器(FM)的软元件。
        //KEYENCE
        //表示XYM 表示
        //XYM 表示时的软元件编号
        //KV-7500/7300
        //继电器R
        //X 0000～1999F*
        //Y 0000～1999F*
        //内部辅助继电器MR M 00000～63999
        //锁存继电器LR L 0000～999F
        //数据存储器DM D 00000～65534
        //扩展数据存储器EM E 00000～65534
        //文件寄存器FM F 00000～32767




        #endregion


        //#region  PLC 指令和响应说明
        //const string ProgramMode = ("4D 30 0D"); //Mn模式更改
        //    const string Run = ("4D 31 0D");
        //    const string OK = ("4F 4B 0D 0A");
        //    const string E0 = ("45 30 0A");  ////软元件编号异常  • 指定的软元件编号、存储体编号、单元 编号、地址超出了范围。
        //    const string E1 = ("45 31 0A");  //E1 :命令异常  • 发送了不支持的指令。• 指定指令的方法不正确。
        //    const string E2 = ("45 32 0A"); //E2 : 未登录程序 • CPU 单元中没有登录程序的状态下，发送了“M1（切换到 RUN 模式）”指令。 
        //    const string E3 = ("45 32 0A"); //E3 : 
        //    const string E4 = ("45 32 0A"); //E4 : 禁止写入• 企图对禁止写入的程序更改计时器、计数器、的设定值
        //    const string E5 = ("45 35 0A"); //E5 : 单元错误 在没有清除 CPU 单元错误的状态下，发送了 “M1（切换到 RUN 模式）”指令。 
        //    const string E6 = ("45 36 0A"); //E5 : 注释读取“RDC”指令选中的软元件中没有登录注释。PLC 的负荷较高，读取注释失败           
        //    const string ER = ("45 52 0D"); //ER : 清除单元中发生的错误
        //    const string EN = ("3F 45 0D "); //?E : 单元错误编号            //错误编号确认 ？E
        //    const string PLC_K = ("3F 4B 0D"); //?K : 用于查看 PLC 的型号。
        //    const string KV7300 = (" 35 34"); // KV-7300 ： ‘54’（ 35H、 34H）  
        //    const string KV7500 = (" 35 35"); // KV-7500 ： ‘55’（ 35H、 35H）
        //    const string MC = ("3F 4D 0D"); //用于查看 CPU 单元当前的运行状态。
        //    const string ST = ("53 54 20"); //强制置位 ST_软元件种类+软元件编号 0D  // 53 54 20 52 30 30 30 30 35 0D（强制置位 R00005）
        //    const string RS = ("52 53 20"); //强制复位 
        //    const string R = ("52");  //  继电器 00000～199915
        //    const string B = ("42"); //链路继电器 0000～7FFF
        //    const string MR = ("4D 52"); //内部辅助继电器 00000～399915
        //    const string LR = ("4C 52"); //锁存继电器 00000～99915
        //    const string CR = ("43 52"); //控制继电器 0000～7915
        //    const string T = ("54"); //定时器 0000～3999
        //    const string C = ("43"); //计数器 C 0000～3999
        //    const string VB = ("56 42"); //工作继电器 VB 0000～F9FF
        //    const string DM = ("44 4D"); //数据存储器  00000～65534  .U  0001～1000 0001～0500
        //    const string EM = ("45 4D"); //扩展数据存储器 00000～65534 .U 0001～1000 0001～0500
        //    const string FM = ("46 4D"); //文件寄存器 00000～32767 .U 0001～1000 0001～0500
        //    const string ZF = ("3F 45 0D"); // 文件寄存器 00000～524287 .U 0001～1000 0001～0500
        //    const string W = ("57"); //链路寄存器 0000～7FFF .U 0001～1000 0001～0500
        //    const string TM = ("54 4D"); //临时数据存储器 TM 000～511 .U 001～512 001～256
        //    const string Z = ("5A"); //变址寄存器 Z 01～12 .U 01～12 01～12
        //    const string TC = ("54 43"); //计时器（当前值） TC 0000～3999 .D 001～120 001～120
        //    const string TS = ("54 53"); //计时器（设定值） TS 0000～3999 .D 001～120 001～120
        //    const string CC = ("43 43"); //计数器（当前值） CC 0000～3999 .D 001～120 001～120
        //    const string CS = ("43 53 "); //计数器（设定值） CS 0000～3999 .D 001～120 001～120
        //    const string AT = ("41 54"); //数字微调器 AT 0～7 .D 1～8 1～8
        //    const string CM = ("43 4D"); //控制存储器 CM 0000～5999 .U 0001～1000 0001～0500
        //    const string VM = ("5A"); //工作存储器 VM 00000～50999 .U 0001～1000 0001～0500
        //    const string _0 = ("30"); //0
        //    const string _1 = ("31"); //1
        //    const string _2 = ("32"); //2
        //    const string _3 = ("33"); //3
        //    const string _4 = ("34"); //4
        //    const string _5 = ("35"); //5
        //    const string _6 = ("36"); //6
        //    const string _7 = ("37"); //7
        //    const string _8 = ("38"); //8
        //    const string _9 = ("39"); //9
        //    const string STS = ("53 54 53 20"); //<连续强制置位> STS 软元件种类+软元件编号 写入个数 0D //   53 54 53 20 52 30 30 30 30 35 20 30 31 30 0D（强制置位 R00005-R00015）
        //    const string RSS = ("52 53 53 20"); //<连续强制置位 RSS 软元件种类+软元件编号 写入个数 0D 写入01-16
        //    const string RD = ("52 44 20"); //RD: 读取一个指定软元件的数据。 RD 软元件种类+软元件编号+数据格式+0D  //RD 52 44 20 52 30 30 30 31 30 0D 读取R00010的数据
        //    const string RDS = ("52 44 53 20"); //RDS: 连续读取指定个数的软元件的数据。
        //    const string DOTU = ("2E 55 20"); //U
        //    const string DOTS = ("2E 53 20"); //S
        //    const string DOTD = ("2E 44 20"); //D 
        //    const string DOTL = ("2E 4C 20"); //L
        //    const string DOTH = ("2E 48 20"); //H
        //    const string WR = ("57 52 20"); //WR :将数据写入指定的软元件。 WR 软元件种类 软元件编号 数据格式 数据 0D
        //    const string WRS = ("57 52 53 20"); //WRS :连续写入指定个数的数据。 WRS 软元件种类 软元件编号 数据格式 写入个数 数据1 数据2 .... 数据n 0D 
        //    const string MBS = ("4D 42 53 20");
        //    const string MWS = ("4D 57 53 20");
        //    const string MBR = ("4D 42 52 0D 20"); //指令 读取软元件登录表 M B R CR ||  4DH 42H 52H 0DH
        //    const string MWR = ("4D 57 52 0D 20"); // <读取字软元件登录表>  M W R CR || 4DH 57H 52H 0DH
        //    const string RDC = ("52 44 43 20"); ////指令  RDC 用于读取指定软元件的注释 RDC 软元件种类R 软元件编号100 Cr || 52 44 43 20 52 31 30 30 0D
        //    const string BE = ("42 45 20"); // 库编号 ：对于文件寄存器的库编号按照 0～15 的范围进行指定。 BE 库编号0 Cr || 42 45 20  30 0D
        //    const string URD = ("55 52 44 20"); //URD 用于从扩展单元缓冲存储器中连续读取指定个数的数据。
        //    const string UWR = ("55 57 52 20"); //用于向扩展单元缓冲存储器连续写入指定个数的数据。

        //    #endregion


        #region  PLC读写函数
        public PLC(string ip, int port)
        {
            _PLCTcpClient = new TcpClient();
            PLC_Port = port;
            PLC_IP = ip;
        }

        /// <summary>
        /// 向PLC读取连续数据 字符串数据
        /// </summary>
        /// <param name="Qtype">轮询的指令</param>
        /// <param name="type">软元件类别</param>
        /// <param name="startByte">起始位</param>
        /// <param name="format">格式 .U .L .D .H</param>
        /// <param name="numberOfBits">读取的数量</param>
        /// <returns></returns>
        public static string QueryPLC(QueryType Qtype, string type, int startByte, string format, int numberOfBits)
        {
            string Str = "";
            string Cr = "0D";
            byte[] ReceiveBuff = new byte[128];
            switch (Qtype)
            {
                case QueryType.ST:
                    Str = "ST " + type + startByte + Cr;
                    break;
                case QueryType.RS:
                    Str = "RS " + type + startByte;
                    break;
                case QueryType.STS:
                    Str = "STS " + type + startByte + " " + numberOfBits + Cr;
                    break;
                case QueryType.RSS:
                    Str = "RSS " + type + startByte + " " + numberOfBits + Cr;
                    break;
                case QueryType.RD:
                    Str = "RD " + type + startByte + format + Cr;
                    break;
                case QueryType.RDS:
                    Str = "RDS " + type + startByte + format + " " + numberOfBits + Cr;
                    break;
                case QueryType.RDE:
                    Str = "RDE " + type + startByte + format + " " + numberOfBits + Cr;
                    break;
                case QueryType.URD: //读取扩展单元缓冲存储器
                    Str = "URD " + type + startByte + format + " " + numberOfBits;
                    break;
                case QueryType.MBR: //读取位软元件
                    Str = "MBR ";
                    break;
                case QueryType.MWR: //读取字软元件
                    Str = "MWR ";
                    break;
                //case QueryType.WR:
                //    Str = "WR " + type + startByte + format + " " + 
                default:
                    break;

            }
            return Str;

        }

        internal void QueryPLC(string v)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// PLC数据单个字节写入 MBS软元件位登录 MWS 软元件字登录
        /// </summary>
        /// <param name="Qtype"></param>
        /// <param name="type"></param>
        /// <param name="startByte"></param>
        /// <param name="format"></param>
        /// <param name="data"></param>
        /// <param name="numberOfBits"></param>
        /// <returns></returns>
        public static string QueryPLC(QueryType Qtype, string type, int startByte, string format, int data, int numberOfBits)
        {
            string Str = "";
            string Cr = "0D";
            byte[] ReceiveBuff = new byte[128];
            switch (Qtype)
            {
                case QueryType.WR:
                    Str = "WR " + type + startByte + format + " " + data;
                    break;
                case QueryType.MBS:
                    Str = "MBS " + type + startByte + " ";
                    break;
                case QueryType.RDC:
                    Str = "RDC " + type + startByte;
                    break;
                case QueryType.BE:
                    Str = "BE " + type;
                    break;
                default:
                    break;
            }
            return Str + Cr;
        }

        /// <summary>
        /// PLC中连续写入或读取软元件信息
        /// </summary>
        /// <param name="Qtype">读取指令</param>
        /// <param name="type">软元件R MR LR </param>
        /// <param name="startByte">起始地址</param>
        /// <param name="format">格式 .U .L .H/param>
        /// <param name="data">要发送的数组/数据串</param>
        /// <param name="numberOfBits">发送位数</param>
        /// <returns></returns>
        public static string QueryPLC(QueryType Qtype, char type, int startByte, char format, int[] data, int numberOfBits)
        {
            string Str = "";
            string Cr = "0D";
            byte[] ReceiveBuff = new byte[128];
            string QData = "";
            foreach (int i in data)
            {
                string.Join(" ", type + QData, i);
            }
            switch (Qtype)
            {
                case QueryType.WRS: //不确定能否成功 需要每一次一个数据格式和软元件编号 数据格式+软元件编号
                    Str = "WRS " + type + startByte + format + " " + data;
                    break;
                case QueryType.MBS: //不确定能否成功 需要每一次一个数据格式和软元件编号 数据格式+软元件编号
                    Str = "MBS " + type + startByte + " " + QData;
                    break;
                case QueryType.RDC: //不确定能否成功 需要每一次一个数据格式和软元件编号 数据格式+软元件编号
                    Str = "MWS " + type + startByte + " " + QData;
                    break;
                case QueryType.BE:
                    Str = "MBR " + type;
                    break;
                default:
                    break;
                case QueryType.UWR:
                    Str = "UWR " + numberOfBits + startByte + format + data;
                    break;
            }
            return Str + Cr;
        }


        public static string QueryPLC(QueryType Qtype, string type, int startByte)
        {
            string Str = "";
            string Cr = "0D";
            byte[] ReceiveBuff = new byte[128];
            switch (Qtype)
            {
                case QueryType.ST:
                    Str = ST + type + startByte + Cr;
                    break;
                case QueryType.RS:
                    Str = RS + type + startByte + Cr;
                    break;
                case QueryType.MBR: //读取位软元件
                    Str = MBR + Cr;
                    break;
                case QueryType.MWR: //读取字软元件
                    Str = MWR + Cr;
                    break;
                default:
                    break;

            }
            return Str;

        }


        /// <summary>
        /// 向PLC读取正常或错误指令
        /// </summary>
        /// <param name="QType"></param>
        /// <returns></returns>
        public static string QueryPLC(QueryType QType)
        {
            string Str = "";
            switch (QType)
            {
                case QueryType.E0:
                    Str = "内容：软元件编号异常+原因：1.指定的软元件编号、存储体编号、单元编号、地址超出了范围。2.指定了程序中没有使用的计时器、计数器、CTH、CTC 编号。3.没有执行监控器登录，但是执行了监控器读取。+处理办法：1.请指定规定范围内的编号。2.请确认程序，并指定程序使用的编号。3.请在监控器读取之前执行监控器登录。";
                    break;
                case QueryType.E1:
                    Str = "内容：指令异常+原因：1.发送了不支持的指令。2.指定指令的方法不正确。+处理办法：1.请确认并发送正确的指令。";
                    break;
                case QueryType.E2:
                    Str = "内容：程序未登录：1.CPU 单元中没有登录程序的状态下，发送了“M1（切换到 RUN 模式）”指令。2.CPU 单元的 RUN/PROG 开关在 PROG状态下，发送了“M1（切换到 RUN 模式）”指令。+处理办法：1.请在 CPU 单元中登录程序后发送指令。2.请将 CPU 单元的 RUN/PROG 开关切换到 RUN。";
                    break;
                case QueryType.E4:
                    Str = "内容：禁止写入+原因：1.企图对禁止写入的程序更改计时器、计数器、的设定值。2.指定了程序中没有使用的计时器、计数器、CTH、CTC 编号。+处理办法：1请取消程序的禁止写入后，重新发送指令。";
                    break;
                case QueryType.E5:
                    Str = "内容：单元错误+原因：1.在没有清除 CPU 单元错误的状态下，发送了 “M1（切换到 RUN 模式）”指令。+处理办法：1.请清除 CPU 单元的错误和错误原因后，重新发送指令。";
                    break;
                case QueryType.E6:
                    Str = "内容：无注释+原因：1.注释读取“RDC”指令选中的软元件中没有登录注释。2.PLC 的负荷较高，读取注释失败。+处理办法：1.需要时，请登录软元件的注释。2.请在 PLC 负荷较低时执行，或重试。";
                    break;
                case QueryType.OK:
                    Str = "OK ：指令正常处理时，输入表示该状态的代码“OK”。";
                    break;

            }
            return Str;
        }



        /// <summary>
        /// 向PLC读取或者写入单个Hex数值
        /// </summary>
        /// <param name="Qtype">指令类型</param>
        /// <param name="type">软元件类型 R MR CR LR</param>
        /// <param name="startByte">起始编号 100 200 300</param>
        /// <param name="format">格式 .U .L .H </param>
        /// <param name="numberOfBits">写入或读取的位数</param>
        /// <returns></returns>
        public static string ReadHexString(QueryType Qtype, string type, string startByte, string format, string numberOfBits)
        {
            string Str = "";
            string Cr = "0D";
            byte[] BType = HexStringToBinary(type);
            byte[] BStartByte = HexStringToBinary(startByte);
            byte[] BFormat = HexStringToBinary(format);
            byte[] BNumber = HexStringToBinary(numberOfBits);
            byte[] ReceiveBuff = new byte[128];


            switch (Qtype)
            {
                case QueryType.ST:
                    Str = ST + BType + BStartByte + Cr;
                    break;
                case QueryType.RS:
                    Str = RS + BType + BStartByte + Cr;
                    break;
                case QueryType.STS:
                    Str = STS + BType + BStartByte + " " + BNumber + Cr;
                    break;
                case QueryType.RSS:
                    Str = RSS + BType + BStartByte + " " + BNumber + Cr;
                    break;
                case QueryType.RD:
                    Str = RD + BType + BStartByte + BFormat + Cr;
                    break;
                case QueryType.RDS:
                    Str = RDS + BType + BStartByte + BFormat + " " + BNumber + Cr;
                    break;
                case QueryType.URD: //读取扩展单元缓冲存储器
                    Str = URD + BType + BStartByte + BFormat + " " + BNumber + Cr;
                    break;
                case QueryType.MBR: //读取位软元件
                    Str = MBR;
                    break;
                case QueryType.MWR: //读取字软元件
                    Str = MWR;
                    break;
                //case QueryType.WR:
                //    Str = "WR " + type + startByte + format + " " + 
                default:
                    break;

            }
            return Str;

        }

        /// <summary>
        /// 向ＰＬＣ发送单个指令
        /// </summary>
        /// <param name="Qtype"></param>
        /// <returns></returns>
        public static string ReadHexString(QueryType Qtype)
        {
            string Str = "";
            string Cr = "0D";
            byte[] ReceiveBuff = new byte[128];


            switch (Qtype)
            {
                case QueryType.ProgramMode://指定“0”时，CPU 单元切换到 PROGRAM 模式。
                    Str = ProgramMode;
                    break;
                case QueryType.Run:  //指定“1”时，CPU 单元切换到 RUN 模式。
                    Str = Run;
                    break;
                case QueryType.OK: //OK ：指令正常处理时，输入表示该状态的代码“OK”。
                    Str = "OK";
                    break;
                case QueryType.ER: //用于清除 CPU 单元中发生的错误。ER 清除错误
                    Str = ER;
                    break;
                case QueryType.EN: //用于检查 CPU 单元中发生的错误或异常。可在错误编号表中查看具体错误内容。 ?E 错误编号确认
                    Str = EN;
                    break;
                case QueryType.PLC_K:  //用于查看 PLC 的型号。
                    Str = PLC_K;
                    break;
                case QueryType.MC:  //用于查看 CPU 单元当前的运行状态。
                    Str = MC;
                    break;
                case QueryType.MBR: //MBR ：读取监控器登录后的位软元件值。
                    Str = MBR;
                    break;
                case QueryType.MWR: //MWR ：读取监控器登录后的字软元件值。
                    Str = MWR;
                    break;
                //case QueryType.WR:
                //    Str = "WR " + type + startByte + format + " " + 
                default:
                    break;

            }
            return Str;

        }



        public void PLCConnect()
        {
            try
            {
                _PLCTcpClient.Connect(PLC_IP, PLC_Port);
                _PLCTcpStream = _PLCTcpClient.GetStream();
            }
            catch (Exception e)
            {
                MessageBox.Show(e.ToString());
            }

        }



        public void PLCDisconnet()
        {
            if (_PLCTcpStream != null)
                _PLCTcpStream.Close();
            if (_PLCTcpClient != null)
                _PLCTcpClient.Close();
        }



        public void MonitorSendQuery(string query)
        {
            if (query != null)
            {
                byte[] SendBuff = HslCommunication.BasicFramework.SoftBasic.HexStringToBytes(query);  //16进制转化为byte类型
                _PLCTcpStream.Write(SendBuff, 0, SendBuff.Length);
            }
        }


        public string MonitorReadQuery(int Locate)
        {
            string StringRead = "";
            byte[] ReceiveBuff = new byte[Locate];
            if (_PLCTcpStream.CanRead)
            {
                int ByteRead = _PLCTcpStream.Read(ReceiveBuff, 0, ReceiveBuff.Length);
                string ResultRead = ByteArrayToHexString(ReceiveBuff);
                //string Result = BitConverter.ToString(ReceiveBuff); //将数据转换为16进制
                //string[] Str = Result.Trim().Split('-');
                //string ResultNeed = Str[Locate];
                //string D = Convert.ToString(Convert.ToInt32(ResultNeed, 16));
                //StringRead = D;
                StringRead = ResultRead;
                return StringRead;
            }
            else
            {
                return null;
            }
        }


        public string MonitorReadQuery()
        {
            string StringRead = "";
            byte[] ReceiveBuff = new byte[64];
            if (_PLCTcpStream.CanRead)
            {
                int ByteRead = _PLCTcpStream.Read(ReceiveBuff, 0, ReceiveBuff.Length);
                string Result = BitConverter.ToString(ReceiveBuff); //将数据转换为16进制
                string[] Str = Result.Trim().Split('-');
                string ResultNeed = Str[0];
                string D = Convert.ToString(Convert.ToInt32(ResultNeed, 16));
                StringRead = D;
                return StringRead;
            }
            else
            {
                return null;
            }
        }

        /// <summary>
        /// 上位机读取DB数据
        /// </summary>
        /// <param name="Locate"></param>
        /// <returns></returns>
        public string MonitorReadDB(int Locate)
        {
            string StringRead = "";
            byte[] ReceiveBuff = new byte[64];
            if (_PLCTcpStream.CanRead)
            {
                int ByteRead = _PLCTcpStream.Read(ReceiveBuff, 0, ReceiveBuff.Length);
                string Result = BitConverter.ToString(ReceiveBuff); //将数据转换为16进制
                string[] Str = Result.Trim().Split('-');
                string ResultNeedDB16 = Str[Locate];
                string ResultNeedDB10 = Convert.ToString(Convert.ToInt32(ResultNeedDB16, 16));  //先转换为10进制
                string ResultNeedDB2 = Convert.ToString(Convert.ToUInt32(ResultNeedDB10), 2);   //在转换为2进制

                StringRead = ResultNeedDB2.PadLeft(8, '0');
                return StringRead;
            }
            else
            {
                return null;
            }

        }
        #endregion

        #region Telnet Socket 通信指令
        //向Telnet服务器发送命令
        public void SocketSend(string msg)
        {
            System.Byte[] message = System.Text.Encoding.ASCII.GetBytes(msg.ToCharArray());
            socket.Send(message, message.Length, 0);
        }

        //向Telnet服务器发送命令
        public void SocketSend(char[] chr)
        {
            System.Byte[] message = System.Text.Encoding.ASCII.GetBytes(chr);
            socket.Send(message, message.Length, 0);
        }

        //向Telnet服务器发送数据
        public void SocketSend(byte[] data)
        {
            System.Byte[] message = data;
            socket.Send(message, message.Length, 0);
        }

        //接收数据
        public string Receive()
        {
            //用于接收数据的缓冲
            byte[] buf;
            string result = "";

            int count = socket.Available;
            if (count > 0)
            {
                buf = new byte[count];
                socket.Receive(buf);
                if (CurrentDataMode == DataMode.Hex)
                {
                    result = ByteArrayToHexString(buf);
                    //MessageBox.Show(result);
                    //textBoxReceive.Text = result;
                }
                else
                {
                    result = ProcessOptions(buf);
                    //MessageBox.Show(result);
                    //textBoxReceive.Text = result;
                }
            }

            return result;
        }
        #region
#if false
        //处理命令字符，buf是包含数据的缓冲
        private string ProcessOptions(byte[] buf)
        {
            string strNormal = "";
            int i = 0;
            while (i < buf.Length)
            {
                strNormal += System.Text.Encoding.Default.GetString(buf, i, 1);
                i++;
            }
            return strNormal;
        }
#else
        #region 常量
        const char GO_NORM = (char)0;
        const char SUSP = (char)237;

        const char ABORT = (char)238;
        const char SE = (char)240; //子选项结束Subnegotiation End
        const char NOP = (char)241;
        const char dm = (char)242; //Data Mark
        const char BREAK = (char)243; //BREAK
        const char IP = (char)244; //Interrupt Process
        const char AO = (char)245; //Abort Output
        const char AYT = (char)246; //Are you there
        const char EC = (char)247; //Erase character
        const char EL = (char)248; //Erase Line
        const char GOAHEAD = (char)249; //Go Ahead
        const char SB = (char)250; //子选项开始Subnegotiation Begin

        const char WILL = (char)251;
        const char WONT = (char)252;
        const char DO = (char)253;
        const char DONT = (char)254;
        const char IAC = (char)255;

        const char BINARY = (char)0;
        const char IS = (char)0;
        const char SEND = (char)1;
        const char ECHO = (char)1;
        const char RECONNECT = (char)2;
        const char SGA = (char)3;
        const char AMSN = (char)4;
        const char STATUS = (char)5;
        const char TIMING = (char)6;
        const char RCTAN = (char)7;
        const char OLW = (char)8;
        const char OPS = (char)9;
        const char OCRD = (char)10;
        const char OHTS = (char)11;
        const char OHTD = (char)12;
        const char OFFD = (char)13;
        const char OVTS = (char)14;
        const char OVTD = (char)15;
        const char OLFD = (char)16;
        const char XASCII = (char)17;
        const char LOGOUT = (char)18;
        const char BYTEM = (char)19;
        const char DET = (char)20;
        const char SUPDUP = (char)21;
        const char SUPDUPOUT = (char)22;
        const char SENDLOC = (char)23;
        const char TERMTYPE = (char)24;

        const char EOR = (char)25;
        const char TACACSUID = (char)26;
        const char OUTPUTMARK = (char)27;
        const char TERMLOCNUM = (char)28;
        const char REGIME3270 = (char)29;
        const char X3PAD = (char)30;
        const char NAWS = (char)31;
        const char TERMSPEED = (char)32;
        const char TFLOWCNTRL = (char)33;
        const char LINEMODE = (char)34;
        const char DISPLOC = (char)35;

        const char ENVIRON = (char)36;
        const char AUTHENTICATION = (char)37;
        const char UNKNOWN39 = (char)39;
        const char EXTENDED_OPTIONS_LIST = (char)255;
        const char RANDOM_LOSE = (char)256;

        const char cr = (char)13;	//回车
        const char LF = (char)10;	//换行
        const string BACK = "[P";
        #endregion
        //处理命令字符，buf是包含数据的缓冲
        private string ProcessOptions(byte[] buf)
        {
            string strNormal = "";
            int i = 0;
            while (i < buf.Length)
            {
                if (buf[i] == IAC)
                {
                    switch ((char)buf[++i])
                    {
                        case DO:
                            Console.Write("--------------接收到 DO ");
                            ProcessDo(buf[++i]);
                            break;
                        case DONT:
                            Console.Write("--------------接收到 DONT ");
                            ProcessDont(buf[++i]);
                            break;
                        case WONT:
                            Console.Write("--------------接收到 WONT ");
                            ProcessWont(buf[++i]);
                            break;
                        case WILL:
                            Console.Write("--------------接收到 WILL ");
                            ProcessWill(buf[++i]);
                            break;
                        case IAC:
                            //正常字符
                            strNormal += System.Text.Encoding.Default.GetString(buf, i, 1);
                            break;
                        case SB:
                            //子会话开始
                            int j = 0;
                            while (buf[++i] != SE)
                            {
                                parsedata[j++] = buf[i];
                            }
                            //子会话结束:
                            switch ((char)parsedata[0])
                            {
                                case TERMTYPE:
                                    break;
                                case TERMSPEED:
                                    if (parsedata[1] == 1)
                                    {
                                        Console.WriteLine("发送: SB TERMSPEED 57600,57600");
                                        SocketSend(IAC + SB + TERMSPEED + IS + "57600,57600" + IAC + SE);
                                    }
                                    break;
                            }
                            break;
                        default:
                            Console.WriteLine("无效的命令" + buf[1]);
                            i++;
                            break;
                    };
                }
                else
                {
                    //正常的文字
                    strNormal += System.Text.Encoding.Default.GetString(buf, i, 1);
                }
                i++;
            }
            return strNormal;
        }

        private void ProcessDo(short ch)
        {
            //处理DO，以WILL或者WONT响应
            switch ((char)ch)
            {
                case BINARY:
                    Console.WriteLine(BINARY);
                    SocketSend(new char[] { IAC, WONT, BINARY });
                    Console.WriteLine("发送: WONT BINARY");
                    break;
                case ECHO:
                    Console.WriteLine(ECHO);
                    SocketSend(new char[] { IAC, WONT, ECHO });
                    Console.WriteLine("发送: WONT ECHO");
                    break;
                case SGA:
                    Console.WriteLine(SGA);
                    if (!sw_igoahead)
                    {
                        SocketSend(new char[] { IAC, WILL, SGA });
                        Console.WriteLine("发送: WILL SGA");
                        sw_igoahead = true;
                    }
                    else
                    {
                        Console.WriteLine("不发送响应");
                    }
                    break;
                case TERMSPEED:
                    Console.WriteLine(TERMSPEED);
                    SocketSend(new char[] { IAC, WILL, TERMSPEED });
                    Console.WriteLine("发送: WILL TERMSPEED");

                    SocketSend(IAC + SB + TERMSPEED + (char)0 + "57600,57600" +
                                                          IAC + SE);
                    Console.WriteLine("发送:SB TERMSPEED 57600");
                    break;
                case TFLOWCNTRL:
                    Console.WriteLine(TFLOWCNTRL);
                    SocketSend(new char[] { IAC, WONT, TFLOWCNTRL });
                    Console.WriteLine("发送: WONT TFLOWCNTRL");
                    break;
                case LINEMODE:
                    Console.WriteLine(LINEMODE);
                    SocketSend(new char[] { IAC, WONT, LINEMODE });
                    Console.WriteLine("发送: WONT LINEMODE");
                    break;
                case STATUS:
                    Console.WriteLine(STATUS);
                    SocketSend(new char[] { IAC, WONT, STATUS });
                    Console.WriteLine("发送: WONT STATUS");
                    break;
                case TIMING:
                    Console.WriteLine(TIMING);
                    SocketSend(new char[] { IAC, WONT, TIMING });
                    Console.WriteLine("发送: WONT TIMING");
                    break;
                case DISPLOC:
                    Console.WriteLine(DISPLOC);
                    SocketSend(new char[] { IAC, WONT, DISPLOC });
                    Console.WriteLine("发送: WONT DISPLOC");
                    break;
                case ENVIRON:
                    Console.WriteLine(ENVIRON);
                    SocketSend(new char[] { IAC, WONT, ENVIRON });
                    Console.WriteLine("发送: WONT ENVIRON");
                    break;
                case UNKNOWN39:
                    Console.WriteLine(UNKNOWN39);
                    SocketSend(new char[] { IAC, WILL, UNKNOWN39 });
                    Console.WriteLine("发送: WILL UNKNOWN39");
                    break;
                case AUTHENTICATION:
                    Console.WriteLine(AUTHENTICATION);
                    SocketSend(new char[] { IAC, WONT, AUTHENTICATION });
                    Console.WriteLine("发送: WONT AUTHENTICATION");
                    Console.WriteLine("发送: SB AUTHENTICATION");
                    SocketSend(IAC + SB + AUTHENTICATION + (char)0 + (char)0 + (char)0 + (char)0 + "" + IAC + SE);
                    break;
                default:
                    Console.WriteLine("未知的选项");
                    break;
            }
        }

        //处理DONT
        private void ProcessDont(short ch)
        {
            switch ((char)ch)
            {
                case SE:
                    Console.WriteLine(SE);
                    Console.WriteLine("接收到: RECEIVED SE");
                    break;
                case ECHO:
                    Console.WriteLine(ECHO);
                    if (!sw_echo)
                    {
                        sw_echo = true;
                        SocketSend(new char[] { IAC, WONT, ECHO });
                        Console.WriteLine("发送: WONT ECHO");
                    }
                    break;
                case SGA:
                    Console.WriteLine(SGA);
                    if (!sw_ugoahead)
                    {
                        SocketSend(new char[] { IAC, WONT, SGA });
                        Console.WriteLine("发送: WONT SGA");
                        sw_ugoahead = true;
                    }
                    break;
                case TERMSPEED:
                    Console.WriteLine(TERMSPEED);
                    SocketSend(new char[] { IAC, WONT, TERMSPEED });
                    Console.WriteLine("发送: WONT TERMSPEED");
                    break;
                case TFLOWCNTRL:
                    Console.WriteLine(TFLOWCNTRL);
                    SocketSend(new char[] { IAC, WONT, TFLOWCNTRL });
                    Console.WriteLine("发送: WONT TFLOWCNTRL");
                    break;
                case STATUS:
                    Console.WriteLine(STATUS);
                    SocketSend(new char[] { IAC, WONT, STATUS });
                    Console.WriteLine("发送: WONT STATUS");
                    break;
                case TIMING:
                    Console.WriteLine(TIMING);
                    SocketSend(new char[] { IAC, WONT, TIMING });
                    Console.WriteLine("发送: WONT TIMING");
                    break;
                case DISPLOC:
                    Console.WriteLine(DISPLOC);
                    SocketSend(new char[] { IAC, WONT, DISPLOC });
                    Console.WriteLine("发送: WONT DISPLOC");
                    break;
                case ENVIRON:
                    Console.WriteLine(ENVIRON);
                    SocketSend(new char[] { IAC, WONT, ENVIRON });
                    Console.WriteLine("发送: WONT ENVIRON");
                    break;
                case UNKNOWN39:
                    Console.WriteLine(UNKNOWN39);
                    SocketSend(new char[] { IAC, WILL, UNKNOWN39 });
                    Console.WriteLine("发送: WILL UNKNOWN39");
                    break;
                default:
                    break;
            }
        }

        //处理WONT
        private void ProcessWont(short ch)
        {
            switch ((char)ch)
            {
                case ECHO:
                    Console.WriteLine(ECHO);
                    if (sw_echo)
                    {
                        sw_echo = false;
                        SocketSend(new char[] { IAC, DONT, ECHO });
                        Console.WriteLine("发送: DONT ECHO");
                    }
                    break;
                case SGA:
                    Console.WriteLine(SGA);
                    SocketSend(new char[] { IAC, DONT, SGA });
                    Console.WriteLine("发送: DONT SGA");
                    sw_igoahead = false;
                    break;
                case TERMSPEED:
                    Console.WriteLine(TERMSPEED);
                    SocketSend(new char[] { IAC, DONT, TERMSPEED });
                    Console.WriteLine("发送: DONT TERMSPEED");
                    break;
                case TFLOWCNTRL:
                    Console.WriteLine(TFLOWCNTRL);
                    SocketSend(new char[] { IAC, DONT, TFLOWCNTRL });
                    Console.WriteLine("发送: DONT TFLOWCNTRL");
                    break;
                case LINEMODE:
                    Console.WriteLine(LINEMODE);
                    SocketSend(new char[] { IAC, DONT, LINEMODE });
                    Console.WriteLine("发送: DONT LINEMODE");
                    break;
                case STATUS:
                    Console.WriteLine(STATUS);
                    SocketSend(new char[] { IAC, DONT, STATUS });
                    Console.WriteLine("发送: DONT STATUS");
                    break;
                case TIMING:
                    Console.WriteLine(TIMING);
                    SocketSend(new char[] { IAC, WONT, TIMING });
                    Console.WriteLine("发送: WONT TIMING");
                    break;
                case DISPLOC:
                    Console.WriteLine(DISPLOC);
                    SocketSend(new char[] { IAC, DONT, DISPLOC });
                    Console.WriteLine("发送: DONT DISPLOC");
                    break;
                case ENVIRON:
                    Console.WriteLine(ENVIRON);
                    SocketSend(new char[] { IAC, DONT, ENVIRON });
                    Console.WriteLine("发送: DONT ENVIRON");
                    break;
                case UNKNOWN39:
                    Console.WriteLine(UNKNOWN39);
                    SocketSend(new char[] { IAC, DONT, UNKNOWN39 });
                    Console.WriteLine("发送: DONT UNKNOWN39");
                    break;
                default:
                    Console.WriteLine("未知的选项");
                    break;
            }
        }

        //处理WILL，以DO或者DONT响应
        private void ProcessWill(short ch)
        {
            switch ((char)ch)
            {
                case ECHO:
                    Console.WriteLine(ECHO);
                    if (!sw_echo)
                    {
                        sw_echo = true;
                        SocketSend(new char[] { IAC, DO, ECHO });
                        Console.WriteLine("发送: DO ECHO");
                    }
                    break;
                case SGA:
                    Console.WriteLine(SGA);
                    if (!sw_ugoahead)
                    {
                        SocketSend(new char[] { IAC, DO, SGA });
                        Console.WriteLine("发送: DO SGA");
                        sw_ugoahead = true;
                    }
                    else
                    {
                        Console.WriteLine("不发送响应");
                    }
                    break;
                case TERMTYPE:
                    Console.WriteLine("TERMTYPE");
                    if (!sw_termsent)
                    {
                        SocketSend(new char[] { IAC, WILL, TERMTYPE });
                        SocketSend(IAC + SB + TERMTYPE + (char)0 + "VT100" + IAC + SE);
                        sw_termsent = true;
                        Console.WriteLine("发送: SB TERMTYPE VT100");
                    }
                    break;
                case TERMSPEED:
                    Console.WriteLine(TERMSPEED);
                    SocketSend(new char[] { IAC, DONT, TERMSPEED });
                    Console.WriteLine("发送: DONT TERMSPEED");
                    break;
                case TFLOWCNTRL:
                    Console.WriteLine(TFLOWCNTRL);
                    SocketSend(new char[] { IAC, DONT, TFLOWCNTRL });
                    Console.WriteLine("发送: DONT TFLOWCNTRL");
                    break;
                case LINEMODE:
                    Console.WriteLine(LINEMODE);
                    SocketSend(new char[] { IAC, WONT, LINEMODE });
                    Console.WriteLine("发送: WONT LINEMODE");
                    break;
                case STATUS:
                    Console.WriteLine(STATUS);
                    SocketSend(new char[] { IAC, DONT, STATUS });
                    Console.WriteLine("发送: DONT STATUS");
                    break;
                case TIMING:
                    Console.WriteLine(TIMING);
                    SocketSend(new char[] { IAC, DONT, TIMING });
                    Console.WriteLine("发送: DONT TIMING");
                    break;
                case DISPLOC:
                    Console.WriteLine(DISPLOC);
                    SocketSend(new char[] { IAC, DONT, DISPLOC });
                    Console.WriteLine("发送: DONT DISPLOC");
                    break;
                case ENVIRON:
                    Console.WriteLine(ENVIRON);
                    SocketSend(new char[] { IAC, DONT, ENVIRON });
                    Console.WriteLine("发送: DONT ENVIRON");
                    break;
                case UNKNOWN39:
                    Console.WriteLine(UNKNOWN39);
                    SocketSend(new char[] { IAC, DONT, UNKNOWN39 });
                    Console.WriteLine("发送: DONT UNKNOWN39");
                    break;
                default:
                    Console.WriteLine("未知的选项");
                    break;
            }
        }
#endif
        #endregion
        public void TelnetThread()
        {
            while (socket.Connected)
            {
                try
                {
                    string str = Receive();
                    str = str.Replace("\0", "");
                    string delim = "\b";
                    str = str.Trim(delim.ToCharArray());
                    if (str.Length > 0)
                    {
                        Console.WriteLine(str);
                        //Dispatcher.BeginInvoke(
                        //    new Action(
                        //        delegate
                        //        {
                        //            this.textBoxReceive.Text = str;
                        //            Paragraph paragraphText = new Paragraph();
                        //            paragraphText.Inlines.Add(str);
                        //            this.rtbText.Document.Blocks.Add(paragraphText);
                        //        }
                        //    )
                        //    );

                        //MessageBox.Show(str);

                        if (str == OUTPUTMARK + BACK)
                        {
                            ////BackupSpace键处理
                            //this.rtbConsole.IsReadOnly = false;
                            //int curpos = rtbConsole.SelectionStart;
                            //this.rtbConsole.Select(curpos - 1, 1);
                            //this.rtbConsole.SelectedText = "";
                            //this.rtbConsole.IsReadOnly = true;
                        }
                        else
                        {
                            //Log(LogMsgType.Incoming, str);
                            logNet.WriteDebug(str);
                        }
                    }
                    Thread.Sleep(100);

                }
                catch (Exception e)
                {
                    Console.WriteLine(e.ToString());
                    //MessageBox.Show(e.ToString());
                }
            }
            //sbpStatus.Content = "状态：已断开";
        }


        public string TelnetThread(string str)
        {



            while (socket.Connected)
            {

                str = Receive();
                str = str.Replace("\0", "");
                string delim = "\b";
                str = str.Trim(delim.ToCharArray());
                Thread.Sleep(100);

            }

            return str;
        }

        public void Connect()
        {
            sw_igoahead = false;
            sw_ugoahead = true;
            sw_igoahead = false;
            sw_echo = true;
            sw_termsent = false;

            //Console.WriteLine("连接服务器" + txtRemoteAddress.Text + "...");
            logNet.WriteDebug("连接到服务器：" + PLC_K + " " + PLC_IP + PLC_Port);
            socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, 5000);

            //IPAddress ipAdd = IPAddress.Parse("192.168.1.105");
            //int port = System.Convert.ToInt32("8501");


            //IPAddress ipAdd = IPAddress.Parse("169.254.51.81");
            //int port = System.Convert.ToInt32("8501");


            IPAddress[] AddressList = Dns.GetHostByName(Dns.GetHostName()).AddressList;
            string LocalIP = AddressList[0].ToString();


            IPAddress ipAdd = IPAddress.Parse(LocalIP);
            //IPAddress ipAdd = IPAddress.Parse("192.158.125.119");

            int port = System.Convert.ToInt32("8501");

            IPEndPoint hostEndPoint = new IPEndPoint(ipAdd, port);

            try
            {
                socket.Connect(hostEndPoint);
            }
            catch (Exception e)
            {
                //Console.WriteLine(e.ToString());
                logNet.WriteError(e.ToString());
                //this.sbpStatus.Content = "状态：服务器未准备好";
                return;
            }

            if (socket.Connected)
            {
                //更新状态
                //sbpStatus.Content = "状态：已连接";
                //sbpHost.Text = "服务器地址：" + txtRemoteAddress.Text;

                Thread thread = new Thread(new ThreadStart(this.TelnetThread));
                thread.Start();
                //Control.CheckForIllegalCrossThreadCalls = false;
            }
        }

        public void Disconnect()
        {
            if (socket != null && socket.Connected)
            {
                socket.Shutdown(SocketShutdown.Both);
                socket.Close();
            }
            //sbpStatus.Content = "状态：断开连接...";

        }

        #endregion


        #region   Telnet通信

        public void SendData(string str)
        {
            if (CurrentDataMode == DataMode.Text)
            {
                // Send the user's text straight out the port
                SocketSend(str);

                // Show in the terminal window the user's text
                //Log(LogMsgType.Outgoing, txtSendData.Text + "\n");
            }
            else
            {
                try
                {
                    // Convert the user's string of hex digits (ex: B4 CA E2) to a byte array
                    byte[] data = HexStringToByteArray(str);

                    // Send the binary data out the port
                    SocketSend(data);

                    // Show the hex digits on in the terminal window
                    //Log(LogMsgType.Outgoing, ByteArrayToHexString(data) + "\n");
                }
                catch (FormatException)
                {
                    // Inform the user if the hex string was not properly formatted
                    //Log(LogMsgType.Error, "Not properly formatted hex string: " + txtSendData.Text + "\n");
                }
            }
            //txtSendData.SelectAll();
        }

        #endregion


        #region ASCII HEX Char 转换函数
        /// <summary> Convert a string of hex digits (ex: E4 CA B2) to a byte array. </summary>
        /// <param name="s"> The string containing the hex digits (with or without spaces). </param>
        /// <returns> Returns an array of bytes. </returns>
        public byte[] HexStringToByteArray(string s)
        {
            s = s.Replace(" ", "");
            byte[] buffer = new byte[s.Length / 2];
            for (int i = 0; i < s.Length; i += 2)
            {
                buffer[i / 2] = (byte)Convert.ToByte(s.Substring(i, 2), 16);
            }
            return buffer;
        }

        /// <summary> Converts an array of bytes into a formatted string of hex digits (ex: E4 CA B2)</summary>
        /// <param name="data"> The array of bytes to be translated into a string of hex digits. </param>
        /// <returns> Returns a well formatted string of hex digits with spacing. </returns>
        public string ByteArrayToHexString(byte[] data)
        {
            StringBuilder sb = new StringBuilder(data.Length * 3);
            foreach (byte b in data)
            {
                sb.Append(Convert.ToString(b, 16).PadLeft(2, '0').PadRight(3, ' '));
            }

            return sb.ToString().ToUpper();
        }

        /// <summary>
        /// 将一条十六进制字符串转换为ASCII
        /// </summary>
        /// <param name="hexstring">一条十六进制字符串</param>
        /// <returns>返回一条ASCII码</returns>
        public static string HexStringToASCII(string hexstring)
        {
            byte[] bt = HexStringToBinary(hexstring);
            string lin = "";
            for (int i = 0; i < bt.Length; i++)
            {
                lin = lin + bt[i] + " ";
            }


            string[] ss = lin.Trim().Split(new char[] { ' ' });
            char[] c = new char[ss.Length];
            int a;
            for (int i = 0; i < c.Length; i++)
            {
                a = Convert.ToInt32(ss[i]);
                c[i] = Convert.ToChar(a);
            }

            string b = new string(c);
            return b;
        }


        /**/
        /// <summary>
        /// 16进制字符串转换为二进制数组
        /// </summary>
        /// <param name="hexstring">用空格切割字符串</param>
        /// <returns>返回一个二进制字符串</returns>
        public static byte[] HexStringToBinary(string hexstring)
        {

            string[] tmpary = hexstring.Trim().Split(' ');
            byte[] buff = new byte[tmpary.Length];
            for (int i = 0; i < buff.Length; i++)
            {
                buff[i] = Convert.ToByte(tmpary[i], 16);
            }
            return buff;
        }


        /// <summary>
        /// 将byte型转换为字符串
        /// </summary>
        /// <param name="arrInput">byte型数组</param>
        /// <returns>目标字符串</returns>
        private string ByteArrayToString(byte[] arrInput)
        {
            int i;
            StringBuilder sOutput = new StringBuilder(arrInput.Length);
            for (i = 0; i < arrInput.Length; i++)
            {
                sOutput.Append(arrInput[i].ToString("X2"));
            }
            //将此实例的值转换为System.String
            return sOutput.ToString();
        }



        /// <summary>
        /// 对接收到的数据进行解包（将接收到的byte型数组解包为Unicode字符串）
        /// </summary>
        /// <param name="recbytes">byte型数组</param>
        /// <returns>Unicode编码的字符串</returns>
        public string disPackage(byte[] recbytes)
        {
            string temp = "";
            foreach (byte b in recbytes)
                temp += b.ToString("X2") + " ";//ToString("X2") 为C#中的字符串格式控制符
            return temp;
        }

        /**
    * int转byte[]
    * 该方法将一个int类型的数据转换为byte[]形式，因为int为32bit，而byte为8bit所以在进行类型转换时，知会获取低8位，
    * 丢弃高24位。通过位移的方式，将32bit的数据转换成4个8bit的数据。注意 &0xff，在这当中，&0xff简单理解为一把剪刀，
    * 将想要获取的8位数据截取出来。
    * @param i 一个int数字
    * @return byte[]
    */
        public static byte[] int2ByteArray(int i)
        {
            byte[] result = new byte[4];
            result[0] = (byte)((i >> 24) & 0xFF);
            result[1] = (byte)((i >> 16) & 0xFF);
            result[2] = (byte)((i >> 8) & 0xFF);
            result[3] = (byte)(i & 0xFF);
            return result;
        }
        /**
         * byte[]转int
         * 利用int2ByteArray方法，将一个int转为byte[]，但在解析时，需要将数据还原。同样使用移位的方式，将适当的位数进行还原，
         * 0xFF为16进制的数据，所以在其后每加上一位，就相当于二进制加上4位。同时，使用|=号拼接数据，将其还原成最终的int数据
         * @param bytes byte类型数组
         * @return int数字
         */
        public static int bytes2Int(byte[] bytes)
        {
            int num = bytes[3] & 0xFF;
            num |= ((bytes[2] << 8) & 0xFF00);
            num |= ((bytes[1] << 16) & 0xFF0000);
            num |= ((bytes[0] << 24) & 0xFF0000);
            return num;
        }

        public static string Int2String(int str)
        {
            string S = Convert.ToString(str);
            return S;
        }

        public static int String2Int(string str)
        {
            int a;
            int.TryParse(str, out a);
            int a1 = Convert.ToInt32(str);
            return a1;
        }


        /*将int转为低字节在后，高字节在前的byte数组
        b[0] = 11111111(0xff) & 01100001
        b[1] = 11111111(0xff) & 00000000
        b[2] = 11111111(0xff) & 00000000
        b[3] = 11111111(0xff) & 00000000
        */
        public byte[] IntToByteArray2(int value)
        {
            byte[] src = new byte[4];
            src[0] = (byte)((value >> 24) & 0xFF);
            src[1] = (byte)((value >> 16) & 0xFF);
            src[2] = (byte)((value >> 8) & 0xFF);
            src[3] = (byte)(value & 0xFF);
            return src;
        }
        //将高字节在前转为int，低字节在后的byte数组(与IntToByteArray2想对应)
        public int ByteArrayToInt2(byte[] bArr)
        {
            if (bArr.Length != 4)
            {
                return -1;
            }
            return (int)((((bArr[0] & 0xff) << 24)
                       | ((bArr[1] & 0xff) << 16)
                       | ((bArr[2] & 0xff) << 8)
   | ((bArr[3] & 0xff) << 0)));
        }

        public static string StringToHexArray(string input)
        {
            char[] values = input.ToCharArray();
            StringBuilder sb = new StringBuilder(input.Length * 3);
            foreach (char letter in values)
            {
                // Get the integral value of the character.
                int value = Convert.ToInt32(letter);
                // Convert the decimal value to a hexadecimal value in string form.
                string hexOutput = String.Format("{0:X}", value);
                sb.Append(Convert.ToString(value, 16).PadLeft(2, '0').PadRight(3, ' '));
            }

            return sb.ToString().ToUpper();

            #endregion

        }
    }
}
